Index: ic/gem.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/gem.c,v retrieving revision 1.31 diff -u -d -u -r1.31 gem.c --- ic/gem.c 17 Oct 2004 21:49:08 -0000 1.31 +++ ic/gem.c 18 Oct 2004 00:38:24 -0000 @@ -1,3 +1,5 @@ +#define GEM_DEBUG 1 +#define GEM_COUNTERS /* $NetBSD: gem.c,v 1.31 2004/10/17 21:49:08 heas Exp $ */ /* @@ -79,6 +81,7 @@ void gem_stop __P((struct ifnet *, int)); int gem_ioctl __P((struct ifnet *, u_long, caddr_t)); void gem_tick __P((void *)); +void gem_pcs_tick __P((void *)); void gem_watchdog __P((struct ifnet *)); void gem_shutdown __P((void *)); int gem_init __P((struct ifnet *)); @@ -99,10 +102,15 @@ static int gem_mii_readreg __P((struct device *, int, int)); static void gem_mii_writereg __P((struct device *, int, int, int)); static void gem_mii_statchg __P((struct device *)); +static int gem_pcs_readreg __P((struct device *, int, int)); +static void gem_pcs_writereg __P((struct device *, int, int, int)); +static void gem_pcs_statchg __P((struct device *)); int gem_mediachange __P((struct ifnet *)); void gem_mediastatus __P((struct ifnet *, struct ifmediareq *)); +static int gem_pcs_intr __P((struct gem_softc *)); + struct mbuf *gem_get __P((struct gem_softc *, int, int)); int gem_put __P((struct gem_softc *, int, struct mbuf *)); void gem_read __P((struct gem_softc *, int, int)); @@ -112,6 +120,7 @@ void gem_power __P((int, void *)); #ifdef GEM_DEBUG +static void gem_reg_dump(struct gem_softc *); #define DPRINTF(sc, x) if ((sc)->sc_ethercom.ec_if.if_flags & IFF_DEBUG) \ printf x #else @@ -136,6 +145,10 @@ int i, error; u_int32_t v; + +sc->sc_debug = 1; +printf("gem_attach\n"); + /* Make sure the chip is stopped. */ ifp->if_softc = sc; gem_reset(sc); @@ -224,7 +237,7 @@ */ /* Announce ourselves. */ - aprint_normal("%s: Ethernet address %s", sc->sc_dev.dv_xname, + printf("%s: Ethernet address %s", sc->sc_dev.dv_xname, ether_sprintf(enaddr)); /* Get RX FIFO size */ @@ -250,23 +263,49 @@ /* 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; + if (sc->sc_flags & (GEM_HAS_SERDES | GEM_HAS_SERIAL)) { + mii->mii_readreg = gem_pcs_readreg; + mii->mii_writereg = gem_pcs_writereg; + mii->mii_statchg = gem_pcs_statchg; + } else { + 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); - mii_attach(&sc->sc_dev, mii, 0xffffffff, + if (!(sc->sc_flags & (GEM_HAS_SERDES | GEM_HAS_SERIAL))) + mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG); +#ifdef GEM_DEBUG +gem_reg_dump(sc); +#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); +printf("No PHY attached\n"); + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); + if (sc->sc_flags & GEM_HAS_SERDES) { + /* SERDES only connects to fiber PHY? */ + ifmedia_add(&sc->sc_media, + IFM_ETHER|IFM_MANUAL|IFM_FDX, 0, NULL); + ifmedia_add(&sc->sc_media, + IFM_ETHER|IFM_MANUAL|IFM_HDX, 0, NULL); + + if (sc->sc_variant != GEM_APPLE_GMAC) + sc->sc_ethercom.ec_capabilities + |= ETHERCAP_JUMBO_MTU; + + sc->sc_flags |= GEM_GIGABIT; + } } else { +printf("PHY attached\n"); /* * Walk along the list of attached MII devices and * establish an `MII instance' to `phy number' @@ -300,12 +339,12 @@ * Internal (MDI0), Serial Link (no MII). */ if (sc->sc_phys[1]) { -#ifdef DEBUG +#ifdef GEM_DEBUG aprint_debug("using external phy\n"); #endif sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL; } else { -#ifdef DEBUG +#ifdef GEM_DEBUG aprint_debug("using internal phy\n"); #endif sc->sc_mif_config &= ~GEM_MIF_CONFIG_PHY_SEL; @@ -397,6 +436,8 @@ #endif callout_init(&sc->sc_tick_ch); + callout_init(&sc->sc_pcstick_ch); + callout_setfunc(&sc->sc_pcstick_ch, gem_pcs_tick, sc); return; /* @@ -468,7 +509,11 @@ printf("%s: cannot reset device\n", sc->sc_dev.dv_xname); } +/* XXX should this wait at all for the reset to complete? */ splx(s); +#ifdef GEM_DEBUG +gem_reg_dump(sc); +#endif } @@ -505,6 +550,7 @@ DPRINTF(sc, ("%s: gem_stop\n", sc->sc_dev.dv_xname)); callout_stop(&sc->sc_tick_ch); + callout_stop(&sc->sc_pcstick_ch); mii_down(&sc->sc_mii); /* XXX - Should we reset these instead? */ @@ -677,6 +723,7 @@ struct gem_rxsoft *rxs; int i, error; +aprint_debug("gem_meminit: \n"); /* * Initialize the transmit descriptor ring. */ @@ -759,6 +806,7 @@ u_int max_frame_size; u_int32_t v; +aprint_debug("gem_init: \n"); s = splnet(); DPRINTF(sc, ("%s: gem_init: calling stop\n", sc->sc_dev.dv_xname)); @@ -805,17 +853,27 @@ bus_space_write_4(t, h, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); /* step 8. Global Configuration & Interrupt Mask */ - 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)); + v = ~(GEM_INTR_TX_INTME|GEM_INTR_TX_EMPTY|GEM_INTR_RX_DONE| + GEM_INTR_RX_NOBUF|GEM_INTR_RX_TAG_ERR|GEM_INTR_MAC_CONTROL| + GEM_INTR_MIF|GEM_INTR_BERR); + v &= (sc->sc_flags & GEM_HAS_SERDES) ? ~GEM_INTR_PCS : 0; + bus_space_write_4(t, h, GEM_INTMASK, 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 */ + if (sc->sc_flags & (GEM_HAS_SERDES | GEM_HAS_SERIAL)) { + bus_space_write_4(t, h, GEM_MAC_SLOT_TIME, GEM_MAC_SLOT_EXT); +#if IS_THIS_CORRECT + /* XXX only necessary for half-duplex? */ + v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); + v |= GEM_MAC_RX_CARR_EXTEND; + bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, v); + v = bus_space_read_4(t, h, GEM_MAC_TX_CONFIG); + v |= GEM_MAC_TX_CARR_EXTEND; + bus_space_write_4(t, h, GEM_MAC_TX_CONFIG, v); +#endif + } /* step 9. ETX Configuration: use mostly default values */ @@ -840,16 +898,19 @@ * The following value is for an OFF Threshold of about 3/4 full * and an ON Threshold of 1/4 full. */ +/*#if might_be_shyte */ bus_space_write_4(t, h, GEM_RX_PAUSE_THRESH, (3 * sc->sc_rxfifosize / 256) | ( (sc->sc_rxfifosize / 256) << 12)); bus_space_write_4(t, h, GEM_RX_BLANKING, (6<<12)|6); +/*#endif*/ /* step 11. Configure Media */ mii_mediachg(&sc->sc_mii); -/* XXXX Serial link needs a whole different setup. */ +gem_pcs_readreg((struct device *) sc, 0, 1); +/* XXX Serial link needs a whole different setup. */ /* step 12. RX_MAC Configuration Register */ v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); @@ -874,6 +935,10 @@ ifp->if_timer = 0; splx(s); +#ifdef GEM_DEBUG +gem_reg_dump(sc); +#endif + return (0); } @@ -886,6 +951,7 @@ const u_char *laddr = LLADDR(ifp->if_sadl); u_int32_t v; +aprint_debug("gem_init_regs: \n"); /* These regs are not cleared on reset */ if (!sc->sc_inited) { @@ -963,6 +1029,9 @@ /* * Enable MII outputs. Enable GMII if there is a gigabit PHY. */ +#if HEASUS + this is squashing stuff from gem_mifinit() + 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) { @@ -971,6 +1040,10 @@ v |= GEM_MAC_XIF_GMII_MODE; } bus_space_write_4(t, h, GEM_MAC_XIF_CONFIG, v); +#endif +#ifdef GEM_DEBUG +gem_reg_dump(sc); +#endif } void @@ -986,6 +1059,10 @@ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; +#if GEM_DEBUG + if (ifp->if_flags & IFF_DEBUG) + aprint_debug("gem_start: \n"); +#endif /* * Remember the previous number of free descriptors and * the first descriptor we'll use. @@ -1239,7 +1316,7 @@ txs->txs_ndescs, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG_RING if (ifp->if_flags & IFF_DEBUG) { int i; printf(" txsoft %p transmit chain:\n", txs); @@ -1284,7 +1361,7 @@ if (txs->txs_mbuf == NULL) { #ifdef DIAGNOSTIC - panic("gem_txintr: null mbuf"); + panic("gem_txintr: null mbuf"); #endif } @@ -1307,9 +1384,9 @@ "GEM_TX_COMPLETION %x\n", bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_TX_STATE_MACHINE), ((long long) bus_space_read_4(sc->sc_bustag, sc->sc_h, - GEM_TX_DATA_PTR_HI) << 32) | + GEM_TX_RING_PTR_HI) << 32) | bus_space_read_4(sc->sc_bustag, sc->sc_h, - GEM_TX_DATA_PTR_LO), + GEM_TX_RING_PTR_LO), bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_TX_COMPLETION))); #endif @@ -1357,8 +1434,10 @@ /* * XXXX Read the lastrx only once at the top for speed. */ +#if GEM_DEBUG_RING DPRINTF(sc, ("gem_rint: sc->rxptr %d, complete %d\n", sc->sc_rxptr, rxcomp)); +#endif /* * Go into the loop at least once. @@ -1392,7 +1471,7 @@ bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0, rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG_RING if (ifp->if_flags & IFF_DEBUG) { printf(" rxsoft %p descriptor %d: ", rxs, i); printf("gd_flags: 0x%016llx\t", (long long) @@ -1472,8 +1551,10 @@ } #endif +#if GEM_DEBUG_RING DPRINTF(sc, ("gem_rint: done sc->rxptr %d, complete %d\n", sc->sc_rxptr, bus_space_read_4(t, h, GEM_RX_COMPLETION))); +#endif return (1); } @@ -1503,7 +1584,7 @@ } #ifdef GEM_DEBUG -/* bzero the packet to check DMA */ + /* bzero the packet to check DMA */ memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size); #endif @@ -1547,6 +1628,124 @@ return (1); } +/* handle PCS (Physical Code Sub-layer) interrupts */ +int +gem_pcs_intr(struct gem_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + bus_space_tag_t bt = sc->sc_bustag; + bus_space_handle_t bh = sc->sc_h; + struct ifmedia *ifm = &sc->sc_media; + uint32_t v; +uint32_t status; +char bits[128]; + +printf("gem_pcs_intr:\n"); +#ifdef GEM_DEBUG + if (sc->sc_debug) + printf("gem_pcs_intr:\n"); +#endif + /* + * 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. + */ + (void) bus_space_read_4(bt, bh, GEM_MII_INTERRUP_STATUS); + (void) bus_space_read_4(bt, bh, GEM_MII_INTERRUP_STATUS); + + /* if the interface ifconfiged up, check the current status */ + if ((ifp->if_flags & IFF_UP) == 0) + return(1); + +aprint_normal("gem_pcs_intr: handling status update\n"); /* XXX */ +v = bus_space_read_4(bt, bh, GEM_MII_STATE_MACHINE); +printf(" mii FSM = %x\n", v & 0x3ff); + + /* XXX check the status and do something about it */ + status = bus_space_read_4(bt, bh, GEM_MII_STATUS); + + if (status & GEM_MII_STATUS_LINK_STS) { +printf(" link status is up %s\n", + bitmask_snprintf(status, GEM_MII_STATUS_BITS, bits, sizeof(bits))); + if (sc->sc_pcs_stat == status) { + printf(" no status change\n"); + return(1); + } + + callout_stop(&sc->sc_pcstick_ch); + /*gem_reset_tx(sc); + gem_reset_rx(sc); */ + + if (status & GEM_MII_STATUS_GB_FDX) { + v = bus_space_read_4(bt, bh, GEM_MAC_XIF_CONFIG); + v |= GEM_MAC_XIF_FDPLX_LED; + bus_space_write_4(bt, bh, GEM_MAC_XIF_CONFIG, v); + } else { + v = bus_space_read_4(bt, bh, GEM_MAC_XIF_CONFIG); + v &= ~GEM_MAC_XIF_FDPLX_LED; + bus_space_write_4(bt, bh, GEM_MAC_XIF_CONFIG, v); + } + v = bus_space_read_4(bt, bh, GEM_MAC_TX_CONFIG); + v |= GEM_MAC_TX_ENABLE; + bus_space_write_4(bt, bh, GEM_MAC_TX_CONFIG, v); + v = bus_space_read_4(bt, bh, GEM_MAC_RX_CONFIG); + v |= GEM_MAC_RX_ENABLE; + bus_space_write_4(bt, bh, GEM_MAC_RX_CONFIG, v); + ifp->if_flags |= IFF_RUNNING; + } else { +printf(" link status is down %s\n", + bitmask_snprintf(status, GEM_MII_STATUS_BITS, bits, sizeof(bits))); + /* ifp->if_flags &= ~IFF_RUNNING;*/ + + gem_stop(ifp, 1); + + /* + * If the intf is set for auto-neg and auto-neg is not running, + * kick it. + */ + if ((IFM_SUBTYPE(ifm->ifm_cur->ifm_media) & IFM_AUTO) && + /* ! */ (status & GEM_MII_STATUS_ANEG_CPT)) { + v = bus_space_read_4(bt, bh, GEM_MII_CONTROL); + v |= GEM_MII_CONTROL_RAN; + bus_space_write_4(bt, bh, GEM_MII_CONTROL, v); + +printf(" kicked ANEG\n"); + } + /* use the ifnet watchdog to check status again */ + /* XXX is this timing too aggressive? */ + callout_schedule(&sc->sc_pcstick_ch, hz * 10); + } + + sc->sc_pcs_stat = status; + + return(1); +} + +/* + * Use a callout to check for auto-negoiation completion for PCS mode. + * + * We would expect to receive a PCS interrupt when it complete, but it + * is missed occassionally. This may be due to the PCS interrupt only + * being asserted when we get light, but I do not know w/o docs. + */ +void +gem_pcs_tick(arg) + void *arg; +{ + struct gem_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + int s; + +#if GEM_DEBUG_MII + if (ifp->if_flags & IFF_DEBUG) + aprint_debug("gem_pcs_tick: \n"); +#endif + + s = splnet(); + gem_pcs_intr(sc); + gem_start(ifp); + splx(s); +} int gem_intr(v) @@ -1576,12 +1775,18 @@ r |= gem_tint(sc); } + /* PCS interrupt indicates change PHY status */ + if (status & GEM_INTR_PCS) { + aprint_normal(" gem_intr: GEM_INTR_PCS\n"); /* XXX */ + r |= gem_pcs_intr(sc); + } + if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0) { GEM_COUNTER_INCR(sc, sc_ev_rxint); r |= gem_rint(sc); } - /* We should eventually do more than just print out error stats. */ + /* XXX 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); if (txstat & ~GEM_MAC_TX_XMIT_DONE) @@ -1626,11 +1831,99 @@ { bus_space_tag_t t = sc->sc_bustag; bus_space_handle_t mif = sc->sc_h; + uint32_t v, v2; + char bits[128]; - /* Configure the MIF in frame mode */ - sc->sc_mif_config = bus_space_read_4(t, mif, GEM_MIF_CONFIG); - sc->sc_mif_config &= ~GEM_MIF_CONFIG_BB_ENA; - bus_space_write_4(t, mif, GEM_MIF_CONFIG, sc->sc_mif_config); +printf("gem_mifinit: 0x%x\n", sc->sc_flags); + + /* Select the data path */ + if (sc->sc_flags & GEM_HAS_SERDES) { + printf("gem_mifinit: GEM_HAS_SERDES\n"); + v = bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_MII_DATAPATH_MODE); + /* the external SERDES connects to a fiber transceiver */ + v &= ~GEM_MII_DATAPATH_SERIAL; + v |= GEM_MII_DATAPATH_SERDES; + + /* power down the serial-link driver and enable sync detect */ + v2 = bus_space_read_4(sc->sc_bustag, sc->sc_h, + GEM_MII_SLINK_CONTROL); + v2 |= GEM_MII_SLINK_POWER_OFF | GEM_MII_SLINK_EN_SYNC_D | + GEM_MII_SLINK_LOOPBACK; + bus_space_write_4(sc->sc_bustag, sc->sc_h, + GEM_MII_SLINK_CONTROL, v2); + + /* set for external phy */ + sc->sc_mif_config = bus_space_read_4(t, mif, GEM_MIF_CONFIG); + sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL; + bus_space_write_4(t, mif, GEM_MIF_CONFIG, sc->sc_mif_config); + + v2 = bus_space_read_4(t, mif, GEM_MAC_XIF_CONFIG); + v2 &= ~GEM_MAC_XIF_MII_LOOPBK; + v2 |= GEM_MAC_XIF_TX_MII_ENA | GEM_MAC_XIF_GMII_MODE + | GEM_MAC_XIF_MII_BUF_ENA; + /* XXX need GEM_MAC_XIF_MII_BUF_ENA if FD ???? + only if internal PHY ???? */ + bus_space_write_4(t, mif, GEM_MAC_XIF_CONFIG, v2); + + v2 = bus_space_read_4(t, mif, GEM_MII_CONFIG); + v2 |= GEM_MII_CONFIG_ENABLE; + bus_space_write_4(t, mif, GEM_MII_CONFIG, v2); + + /* set-up for PCS */ + v2 = bus_space_read_4(t, mif, GEM_MII_CONTROL); + v2 &= ~(GEM_MII_CONTROL_LOOPBK | GEM_MII_CONTROL_POWERDN | + GEM_MII_CONTROL_ISOLATE); + /* XXX this belongs elsewhere, i think it starts autoneg, + which we dont want the + remote to think we're up when we really aren't - if it + were a p2p w/ statics... */ + v2 |= GEM_MII_CONTROL_AUTONEG; + bus_space_write_4(t, mif, GEM_MII_CONTROL, v2); + + /* mark the PCS status as unknown */ + sc->sc_pcs_stat = 0; + + bus_space_write_4(t, mif, GEM_MII_DATAPATH_MODE, v); + DPRINTF(sc, ("gem_mifinit: GEM_MII_DATAPATH %s\n", + bitmask_snprintf(v, GEM_MII_DATAPATH_BITS, bits, + sizeof(bits)))); + } else { + /* XXX should match GEM_HAS_{G}MII here and diddle approp. */ + /* not on ERI + v &= ~GEM_MII_DATAPATH_SERDES; + v |= GEM_MII_DATAPATH_SERIAL; */ + + /* Configure the MIF in frame mode */ + sc->sc_mif_config = bus_space_read_4(t, mif, GEM_MIF_CONFIG); + sc->sc_mif_config &= ~GEM_MIF_CONFIG_BB_ENA; + +/* not on ERI +sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL; */ + bus_space_write_4(t, mif, GEM_MIF_CONFIG, sc->sc_mif_config); + } + /* not on ERI + bus_space_write_4(t, mif, GEM_MII_DATAPATH_MODE, v); + DPRINTF(sc, ("gem_mifinit: GEM_MII_DATAPATH %s\n", + bitmask_snprintf(v, GEM_MII_DATAPATH_BITS, bits, sizeof(bits)))); + */ + +#ifndef TEMP_SLURP_FROM_GEM_MII_STATCHG + /* Set tx full duplex options */ + bus_space_write_4(t, mif, 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 0 + if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) { + v |= GEM_MAC_TX_IGN_CARRIER|GEM_MAC_TX_IGN_COLLIS; + } +#endif + bus_space_write_4(t, mif, GEM_MAC_TX_CONFIG, v); +#endif + +#ifdef GEM_DEBUG +gem_reg_dump(sc); +#endif } /* @@ -1658,7 +1951,7 @@ int n; u_int32_t v; -#ifdef GEM_DEBUG1 +#ifdef GEM_DEBUG if (sc->sc_debug) printf("gem_mii_readreg: phy %d reg %d\n", phy, reg); #endif @@ -1701,7 +1994,7 @@ int n; u_int32_t v; -#ifdef GEM_DEBUG1 +#ifdef GEM_DEBUG if (sc->sc_debug) printf("gem_mii_writereg: phy %d reg %d val %x\n", phy, reg, val); @@ -1790,16 +2083,200 @@ bus_space_write_4(t, mac, GEM_MAC_XIF_CONFIG, v); } +static int heasctr=0; +/* + * PCS (Physical Code Sub-layer) (MII) interface + */ +static int +gem_pcs_readreg(self, phy, reg) + struct device *self; + int phy, reg; +{ + struct gem_softc *sc = (void *)self; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t mif = sc->sc_h; +#ifdef UNUSED + int n; + u_int32_t v; +#endif + +#ifdef GEM_DEBUG + if (sc->sc_debug) + printf("gem_pcs_readreg: phy %d reg %d\n", phy, reg); +#endif + +return 0; +/* XXX + below causes: + +gem_attach: phy discovered by mii_attach(): phy 1, instance 0 +using internal phy +ifmedia_set: no match for 0x20/0xfffffff +panic: ifmedia_set +kdb breakpoint at 1137bf0 +Stopped in pid 0.1 (swapper) at netbsd:cpu_Debugger+0x4: nop +*/ + /* We have at most 2 PHYs */ + if (phy != GEM_PHYAD_EXTERNAL && phy != GEM_PHYAD_INTERNAL) + return(0); + + /* SERDES (and thus PCS) only does external ... afaik */ + /* if (phy != GEM_PHYAD_EXTERNAL) GEM_PHYAD_EXTERNAL appears to be + backwards XXX */ + if (phy != 0) + return(0); + +if (reg == MII_BMSR) { + if (heasctr) + return(8400); + else { + heasctr++; + return(bus_space_read_4(t, mif, GEM_MII_STATUS)); + } +} +/* for the PHYID regs, just return 0 and end-up with ukphy */ +return 1; + +#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 +#if 0 +v = bus_space_read_4(t, mif, GEM_MIF_CONFIG); +v &= ~GEM_MIF_CONFIG_PHY_SEL; +v |= GEM_MIF_CONFIG_PHY_SEL; +bus_space_write_4(t, mif, GEM_MIF_CONFIG, v); +#endif + + return (0); +} + +static void +gem_pcs_writereg(self, phy, reg, val) + struct device *self; + int phy, reg, val; +{ + struct gem_softc *sc = (void *)self; +#ifdef UNUSED + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t mif = sc->sc_h; + int n; + u_int32_t v; +#endif + +aprint_normal("gem_pcs_writereg: \n"); +#ifdef GEM_DEBUG + if (sc->sc_debug) + printf("gem_pcs_writereg: phy %d reg %d val %x\n", + phy, reg, val); +#endif + +return; + +#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 + +} + +static void +gem_pcs_statchg(dev) + struct device *dev; +{ + struct gem_softc *sc = (void *)dev; +#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_h; + u_int32_t v; + +aprint_normal("gem_pcs_statchg: \n"); +#ifdef GEM_DEBUG + if (sc->sc_debug) + aprint_normal("gem_pcs_statchg: status change: phy = %d\n", + sc->sc_phys[instance]); +#endif + +/* think we read GEM_MII_INTERRUP_STATUS and write ~GEM_MII_INTERRUP_LINK */ + /* ack any PCS link interrupt (have to read it twice) */ + (void) bus_space_read_4(t, mac, GEM_MII_INTERRUP_STATUS); + v = bus_space_read_4(t, mac, GEM_MII_INTERRUP_STATUS); + /* v &= ~GEM_MII_INTERRUP_LINK; + bus_space_write_4(t, mac, GEM_MII_INTERRUP_STATUS, v); XXX */ + + /* XXX may not be what triggered the intr??? read GEM_MII_STATUS ??? + ge_hw.c:1817 */ + + +return; + + /* 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; + } + 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; + + /* 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; + + 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 |= GEM_MAC_XIF_MII_BUF_ENA; + bus_space_write_4(t, mac, GEM_MAC_XIF_CONFIG, v); +} + int gem_mediachange(ifp) struct ifnet *ifp; { struct gem_softc *sc = ifp->if_softc; +printf("gem_mediachange:\n"); + if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) return (EINVAL); - return (mii_mediachg(&sc->sc_mii)); + if (sc->sc_flags & GEM_HAS_SERDES) { +printf("gem_mediachange: SERDES\n"); + return (mii_mediachg(&sc->sc_mii)); + } else + return (mii_mediachg(&sc->sc_mii)); } void @@ -1808,16 +2285,33 @@ struct ifmediareq *ifmr; { struct gem_softc *sc = ifp->if_softc; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h; + +#ifdef GEM_DEBUG + if (ifp->if_flags & IFF_DEBUG) + gem_reg_dump(sc); +#endif if ((ifp->if_flags & IFF_UP) == 0) return; - mii_pollstat(&sc->sc_mii); - ifmr->ifm_active = sc->sc_mii.mii_media_active; - ifmr->ifm_status = sc->sc_mii.mii_media_status; + if (sc->sc_flags & GEM_HAS_SERDES) { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = IFM_AVALID; + /* XXX this is not correct for auto-neg, it does not display reality (down/duplux & speed) */ + ifmr->ifm_status = sc->sc_media.ifm_cur->ifm_media; + if (bus_space_read_4(t, h, + GEM_MII_STATUS) & GEM_MII_STATUS_LINK_STS) + ifmr->ifm_status = IFM_ACTIVE; + } else { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = sc->sc_mii.mii_media_active; + ifmr->ifm_status = sc->sc_mii.mii_media_status; + } } -int gem_ioctldebug = 0; +int gem_ioctldebug = 1; /* * Process an ioctl request. */ @@ -1839,6 +2333,12 @@ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); break; +/* XXX should handle these + case SIOCSIFADDR: + case SIOCSIFFLAGS: + case SIOCADDMULTI: + case SIOCDELMULTI: +*/ default: error = ether_ioctl(ifp, cmd, data); if (error == ENETRESET) { @@ -1846,7 +2346,7 @@ * Multicast list has changed; set the hardware filter * accordingly. */ -if (gem_ioctldebug) printf("reset1\n"); +if (gem_ioctldebug) printf("gem_ioctl: reset1\n"); gem_init(ifp); delay(50000); error = 0; @@ -1965,7 +2465,6 @@ } #if notyet - /* * gem_power: * @@ -2003,3 +2502,106 @@ splx(s); } #endif + +#ifdef GEM_DEBUG +/* Dump (aprint) gem registers */ +static void +gem_reg_dump(sc) + struct gem_softc *sc; +{ + bus_space_tag_t bt = sc->sc_bustag; + bus_space_handle_t bh = sc->sc_h; + uint32_t v; + char bits[128]; + + if (! sc->sc_debug) + return; + + printf("%s: gem_reg_dump:\n", sc->sc_dev.dv_xname); + + /* global config register */ + v = bus_space_read_4(bt, bh, GEM_CONFIG); + bitmask_snprintf(v, "\177\020b\0INFBURST\0\0", bits, sizeof(bits)); + aprint_debug("\tGEM_CONFIG = %s\n", bits); + + /* global interrupt mask register */ + v = bus_space_read_4(bt, bh, GEM_INTMASK); + bitmask_snprintf(v, GEM_INTR_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_INTMASK = %s\n", bits); + + /* global error status register */ + v = bus_space_read_4(bt, bh, GEM_ERROR_STATUS); + bitmask_snprintf(v, GEM_ERROR_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_ERROR_STATUS=%s\n", bits); + /* global error mask register */ + v = bus_space_read_4(bt, bh, GEM_ERROR_MASK); + bitmask_snprintf(v, GEM_ERROR_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_ERROR_MASK=%s\n", bits); + + /* global BIF config register */ + v = bus_space_read_4(bt, bh, GEM_BIF_CONFIG); + bitmask_snprintf(v, GEM_BIF_CONFIG_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_BIF_CONFIG=%s\n", bits); + + /* MAC registers */ + /* control mask register */ + v = bus_space_read_4(bt, bh, GEM_MAC_CONTROL_MASK); + bitmask_snprintf(v, GEM_MAC_STATUS_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_CONTROL_MASK=%s\n", bits); + /* control config register */ + v = bus_space_read_4(bt, bh, GEM_MAC_CONTROL_CONFIG); + bitmask_snprintf(v, GEM_MAC_CC_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_CONTROL_CONFIG=%s\n", bits); + /* xif config register */ + v = bus_space_read_4(bt, bh, GEM_MAC_XIF_CONFIG); + bitmask_snprintf(v, GEM_MAC_XIF_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_XIF_CONFIG=%s\n", bits); + /* slot time register */ + v = bus_space_read_4(bt, bh, GEM_MAC_SLOT_TIME); + bitmask_snprintf(v, GEM_MAC_SLOT_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_SLOT_TIME=%s\n", bits); + /* tx config register */ + v = bus_space_read_4(bt, bh, GEM_MAC_TX_CONFIG); + bitmask_snprintf(v, GEM_MAC_TX_CONFIG_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_TX_CONFIG=%s\n", bits); + /* rx config register */ + v = bus_space_read_4(bt, bh, GEM_MAC_RX_CONFIG); + bitmask_snprintf(v, GEM_MAC_RX_CONFIG_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MAC_RX_CONFIG=%s\n", bits); + + /* MIF registers */ + /* mif config register */ + v = bus_space_read_4(bt, bh, GEM_MIF_CONFIG); + bitmask_snprintf(v, GEM_MIF_CONFIG_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MIF_CONFIG=%s\n", bits); + + /* PCS/serial registers should not be touched on the ERI */ + if ( sc->sc_variant == GEM_SUN_ERI) + return; + + /* PCS/serial registers */ + v = bus_space_read_4(bt, bh, GEM_MII_CONTROL); + bitmask_snprintf(v, GEM_MII_CONTROL_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MII_CONTROL=%s\n", bits); + + /* mii status register */ + v = bus_space_read_4(bt, bh, GEM_MII_STATUS); + bitmask_snprintf(v, GEM_MII_STATUS_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MII_STATUS=%s\n", bits); + /* mii config register */ + v = bus_space_read_4(bt, bh, GEM_MII_CONFIG); + bitmask_snprintf(v, GEM_MII_CONFIG_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MII_CONFIG=%s\n", bits); + /* mii datapath register */ + v = bus_space_read_4(bt, bh, GEM_MII_DATAPATH_MODE); + bitmask_snprintf(v, GEM_MII_DATAPATH_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MII_DATAPATH_MODE=%s\n", bits); + /* mii slink control register */ + v = bus_space_read_4(bt, bh, GEM_MII_SLINK_CONTROL); + bitmask_snprintf(v, GEM_MII_SLINK_CONTROL_BITS, bits, sizeof(bits)); + aprint_debug("\tGEM_MII_SLINK_CONTROL=%s\n", bits); + + v = bus_space_read_4(bt, bh, GEM_MII_STATE_MACHINE); + aprint_debug("\tpcs/mii FSM = 0x%x\n", v & 0x3ff); +} +#endif Index: ic/gemreg.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/gemreg.h,v retrieving revision 1.6 diff -u -d -u -r1.6 gemreg.h --- ic/gemreg.h 17 Oct 2004 21:49:08 -0000 1.6 +++ ic/gemreg.h 18 Oct 2004 00:38:24 -0000 @@ -87,8 +87,8 @@ #define GEM_INTR_BITS "\177\020" \ "b\0INTME\0b\1TXEMPTY\0b\2TXDONE\0" \ "b\4RXDONE\0b\5RXNOBUF\0b\6RX_TAG_ERR\0" \ - "b\15PCS\0b\16TXMAC\0b\17RXMAC\0" \ - "b\20MAC_CONTROL\0b\21MIF\0b\22BERR\0\0" \ + "b\xdPCS\0b\xeTXMAC\0b\xfRXMAC\0" \ + "b\x10MAC_CONTROL\0b\x11MIF\0b\x12IBERR\0\0" @@ -96,6 +96,7 @@ #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_BITS "\177\020b\0ACKBAD\0b\1DTRTO\0b\2OTHER\0\0" /* GEM_BIF_CONFIG register bits */ @@ -103,6 +104,8 @@ #define GEM_BIF_CONFIG_HOST_64 0x000000002 /* 64-bit host */ #define GEM_BIF_CONFIG_B64D_DIS 0x000000004 /* no 64-bit data cycle */ #define GEM_BIF_CONFIG_M66EN 0x000000008 +#define GEM_BIF_CONFIG_BITS "\177\020b\0SLOWCLK\0b\1HOST64\0" \ + "b\2B64DIS\0b\3M66EN\0\0" /* GEM_RESET register bits -- TX and RX self clear when complete. */ @@ -234,7 +237,7 @@ #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 +#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 @@ -322,6 +325,7 @@ #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_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 */ @@ -331,6 +335,14 @@ #define GEM_MAC_XIF_MII_BUF_ENA 0x00000010 /* Enable MII recv buffers */ #define GEM_MAC_XIF_LINK_LED 0x00000020 /* force link LED active */ #define GEM_MAC_XIF_FDPLX_LED 0x00000040 /* force FDPLX LED active */ +#define GEM_MAC_XIF_BITS "\177\020b\0TXMIIENA\0b\1MIILOOP\0b\2NOECHO" \ + "\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 */ #define GEM_MAC_TX_ENABLE 0x00000001 /* TX enable */ @@ -344,6 +356,11 @@ #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" \ + "b\6NOBKOFF\0b\7SLOWDN\0b\x8NOFCS\0" \ + "b\x9TXCARREXT\0\0" /* GEM_MAC_RX_CONFIG register bits */ @@ -360,12 +377,17 @@ * 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 */ #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 */ @@ -397,7 +419,7 @@ /* GEM_MIF_CONFIG register bits */ -#define GEM_MIF_CONFIG_PHY_SEL 0x00000001 /* PHY select */ +#define GEM_MIF_CONFIG_PHY_SEL 0x00000001 /* PHY select, 0=MDIO0 */ #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 */ @@ -405,6 +427,8 @@ #define GEM_MIF_CONFIG_MDI1 0x00000200 /* MDIO_1 Data/MDIO_1 atached */ #define GEM_MIF_CONFIG_PHY_ADR 0x00007c00 /* poll PHY address */ /* MDI0 is onboard transceiver MID1 is external, PHYAD 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 */ @@ -418,15 +442,15 @@ */ -/* The GEM PCS/Serial link register. */ +/* 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 /* LP ability 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 +#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 @@ -443,6 +467,9 @@ #define GEM_MII_CONTROL_RAN 0x00000200 /* restart auto negotiation */ #define GEM_MII_CONTROL_FDUPLEX 0x00000100 /* full duplex, always 0 */ #define GEM_MII_CONTROL_COL_TST 0x00000080 /* collision test */ +#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) */ @@ -454,6 +481,9 @@ #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_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_ANLAR reg bits */ @@ -468,8 +498,14 @@ /* GEM_MII_CONFIG reg */ -#define GEM_MII_CONFIG_TIMER 0x0000001c /* link monitor timer values */ +#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_BITS "\177\020b\0PCSENA\0\0" /* @@ -492,7 +528,7 @@ /* GEM_MII_DATAPATH_MODE reg */ #define GEM_MII_DATAPATH_SERIAL 0x00000001 /* Serial link */ #define GEM_MII_DATAPATH_SERDES 0x00000002 /* Use PCS via 10bit interfac */ -#define GEM_MII_DATAPATH_MII 0x00000004 /* Use MII, not PCS */ +#define GEM_MII_DATAPATH_MII 0x00000004 /* Use MII/GMII, not PCS */ #define GEM_MII_DATAPATH_MIIOUT 0x00000008 /* enable serial output on GMII */ #define GEM_MII_DATAPATH_BITS "\177\020" \ "b\0SERIAL\0b\1SERDES\0b\2MII\0b\3MIIOUT\0\0" @@ -506,6 +542,9 @@ #define GEM_MII_SLINK_EMPHASIS 0x00000008 /* 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 \ + "\177\020b\0LOOP\0b\1ENASYNC\0b\2LOCKREF" \ + "\0b\3EMPHASIS\0b\x9PWRDWN\0\0" /* GEM_MII_SLINK_STATUS reg */ Index: ic/gemvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/gemvar.h,v retrieving revision 1.10 diff -u -d -u -r1.10 gemvar.h --- ic/gemvar.h 17 Oct 2004 21:49:08 -0000 1.10 +++ ic/gemvar.h 18 Oct 2004 00:38:24 -0000 @@ -119,6 +119,7 @@ struct mii_data sc_mii; /* MII media control */ #define sc_media sc_mii.mii_media/* shorthand */ struct callout sc_tick_ch; /* tick callout */ + struct callout sc_pcstick_ch; /* PCS tick callout */ /* The following bus handles are to be provided by the bus front-end */ bus_space_tag_t sc_bustag; /* bus tag */ @@ -129,15 +130,25 @@ int sc_phys[2]; /* MII instance -> PHY map */ int sc_mif_config; /* Selected MII reg setting */ + u_int sc_pcs_stat; /* saved PCS status */ 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 */ - u_int sc_flags; /* */ + u_int sc_flags; #define GEM_GIGABIT 0x0001 /* has a gigabit PHY */ +#define GEM_HAS_SERIAL 0x0002 /* has serial PHY */ +#define GEM_HAS_SERDES 0x0004 /* has serdes PHY */ +#define GEM_HAS_MII 0x0008 /* has MII */ +#define GEM_HAS_GMII 0x0010 /* has Gigabit MII */ +#define GEM_FLAGS_DATAPATH_MASK 0x001e +/* XXX #define GEM_FLAGS_LCLMAC 0x8000*/ /* use the local-mac-address */ + + u_int8_t sc_enaddr[ETHER_ADDR_LEN]; /* MAC address */ void *sc_sdhook; /* shutdown hook */ void *sc_powerhook; /* power management hook */ Index: pci/if_gem_pci.c =================================================================== RCS file: /cvsroot/src/sys/dev/pci/if_gem_pci.c,v retrieving revision 1.17 diff -u -d -u -r1.17 if_gem_pci.c --- pci/if_gem_pci.c 17 Oct 2004 21:49:08 -0000 1.17 +++ pci/if_gem_pci.c 18 Oct 2004 00:38:24 -0000 @@ -125,24 +125,63 @@ struct pci_attach_args *pa = aux; struct gem_pci_softc *gsc = (void *)self; struct gem_softc *sc = &gsc->gsc_gem; + pcitag_t tag = pa->pa_tag; pci_intr_handle_t ih; const char *intrstr; char devinfo[256]; uint8_t enaddr[ETHER_ADDR_LEN]; + int node = PCITAG_NODE(tag); - aprint_naive(": Ethernet controller\n"); +printf("gem_attach_pci\n"); + printf(": Ethernet controller\n"); pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); - aprint_normal(": %s (rev. 0x%02x)\n", devinfo, + printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class)); + /* Use flags from autoconf */ + sc->sc_flags |= sc->sc_dev.dv_cfdata->cf_flags; + /* Figure out if the GEM has a serial or SERDES link, or both */ + if (OF_getprop(node, "serial-link", devinfo, sizeof(devinfo)) > 0) { + if (strcmp(devinfo, "disabled") == 0) + sc->sc_flags &= ~GEM_HAS_SERIAL; + else if (strcmp(devinfo, "enabled") == 0) + sc->sc_flags |= GEM_HAS_SERIAL; + printf(", serial-link"); + } + if (OF_getprop(node, "non-serial-link", devinfo, sizeof(devinfo)) > 0) { + sc->sc_flags &= ~GEM_HAS_SERIAL; + printf(", non-serial-link"); + } + if (OF_getprop(node, "shared-pins", devinfo, sizeof(devinfo)) > 0) { + if (strcmp(devinfo, "mii") == 0) { + sc->sc_flags |= GEM_HAS_MII; + printf(", MII"); + } else if (strcmp(devinfo, "gmii") == 0) { + sc->sc_flags |= GEM_HAS_GMII; + printf(", GMII"); + } else if (strcmp(devinfo, "serdes") == 0) { + sc->sc_flags |= GEM_HAS_SERDES; + printf(", SERDES"); + } + } + printf("\n"); + if ((sc->sc_flags & GEM_FLAGS_DATAPATH_MASK) == 0) + printf("%s: no data path defined\n", + sc->sc_dev.dv_xname); + if ((sc->sc_flags & GEM_FLAGS_DATAPATH_MASK) == GEM_FLAGS_DATAPATH_MASK) + printf("%s: both serial-link and SERDES data paths " + "defined\n", sc->sc_dev.dv_xname); + sc->sc_dmatag = pa->pa_dmat; sc->sc_pci = 1; /* XXX */ 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)) + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK) + sc->sc_variant = GEM_SUN_ERI; + else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && + 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 || @@ -156,7 +195,7 @@ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_bustag, &sc->sc_h, NULL, NULL) != 0) { - aprint_error("%s: unable to map device registers\n", + printf("%s: unable to map device registers\n", sc->sc_dev.dv_xname); return; } @@ -176,7 +215,7 @@ node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); if (node == 0) { - aprint_error("%s: unable to locate OpenFirmware node\n", + printf("%s: unable to locate OpenFirmware node\n", sc->sc_dev.dv_xname); return; } @@ -186,21 +225,21 @@ #endif /* macppc */ if (pci_intr_map(pa, &ih) != 0) { - aprint_error("%s: unable to map interrupt\n", + printf("%s: unable to map interrupt\n", sc->sc_dev.dv_xname); return; - } + } intrstr = pci_intr_string(pa->pa_pc, ih); gsc->gsc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, gem_intr, sc); if (gsc->gsc_ih == NULL) { - aprint_error("%s: unable to establish interrupt", + printf("%s: unable to establish interrupt", sc->sc_dev.dv_xname); if (intrstr != NULL) - aprint_normal(" at %s", intrstr); - aprint_normal("\n"); + printf(" at %s", intrstr); + printf("\n"); return; } - aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); + printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); /* Finish off the attach. */ gem_attach(sc, enaddr);