diff options
-rw-r--r-- | share/man/man4/gem.4 | 19 | ||||
-rw-r--r-- | sys/conf/NOTES | 2 | ||||
-rw-r--r-- | sys/dev/gem/if_gem.c | 812 | ||||
-rw-r--r-- | sys/dev/gem/if_gem_pci.c | 165 | ||||
-rw-r--r-- | sys/dev/gem/if_gemreg.h | 148 | ||||
-rw-r--r-- | sys/dev/gem/if_gemvar.h | 66 | ||||
-rw-r--r-- | sys/modules/Makefile | 4 | ||||
-rw-r--r-- | sys/powerpc/conf/NOTES | 1 |
8 files changed, 790 insertions, 427 deletions
diff --git a/share/man/man4/gem.4 b/share/man/man4/gem.4 index 01d0acc..2e0939f 100644 --- a/share/man/man4/gem.4 +++ b/share/man/man4/gem.4 @@ -33,7 +33,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 4, 2007 +.Dd September 26, 2007 .Dt GEM 4 .Os .Sh NAME @@ -74,6 +74,17 @@ Sun ERI 10/100 Mbps Ethernet .It Sun GEM Gigabit Ethernet .El +.Pp +The +following add-on cards are known to work with the +.Nm +driver at this time: +.Pp +.Bl -bullet -compact +.It +Sun Gigabit Ethernet PCI 2.0/3.0 (GBE/P) +(part no.\& 501-4373) +.El .Sh NOTES On sparc64 the .Nm @@ -100,11 +111,7 @@ and the Sun Gigabit Ethernet 2.0/3.0 GBE add-on cards. .Sh CAVEATS Currently the .Nm -driver fails to attach to Sun Gigabit Ethernet 2.0/3.0 (GBE/P) cards, -as the SERDES used on these cards is not supported so far. -The -.Nm -driver will also fail to probe and attach to Sun Gigabit Ethernet 2.0/3.0 (GBE/S) cards, +driver fails to attach to Sun Gigabit Ethernet SBus 2.0/3.0 (GBE/S) cards, as no SBus front-end has been written so far. .Sh SEE ALSO .Xr altq 4 , diff --git a/sys/conf/NOTES b/sys/conf/NOTES index fbbd644..df17803 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1766,6 +1766,7 @@ device miibus # fpa: Support for the Digital DEFPA PCI FDDI. `device fddi' is also needed. # fxp: Intel EtherExpress Pro/100B # (hint of prefer_iomap can be done to prefer I/O instead of Mem mapping) +# gem: Apple GMAC/Sun ERI/Sun GEM # hme: Sun HME (Happy Meal Ethernet) # le: AMD Am7900 LANCE and Am79C9xx PCnet # lge: Support for PCI gigabit ethernet adapters based on the Level 1 @@ -1880,6 +1881,7 @@ device cxgb # Chelsio T3 10 Gigabit Ethernet device dc # DEC/Intel 21143 and various workalikes device fxp # Intel EtherExpress PRO/100B (82557, 82558) hint.fxp.0.prefer_iomap="0" +device gem # Apple GMAC/Sun ERI/Sun GEM device hme # Sun HME (Happy Meal Ethernet) device lge # Level 1 LXT1001 gigabit Ethernet device my # Myson Fast Ethernet (MTD80X, MTD89X) diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c index 60b7a17..cb37ef6 100644 --- a/sys/dev/gem/if_gem.c +++ b/sys/dev/gem/if_gem.c @@ -31,7 +31,7 @@ __FBSDID("$FreeBSD$"); /* - * Driver for Sun GEM ethernet controllers. + * Driver for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers */ #if 0 @@ -80,7 +80,11 @@ __FBSDID("$FreeBSD$"); #include <dev/gem/if_gemreg.h> #include <dev/gem/if_gemvar.h> +CTASSERT(powerof2(GEM_NRXDESC) && GEM_NRXDESC >= 32 && GEM_NRXDESC <= 8192); +CTASSERT(powerof2(GEM_NTXDESC) && GEM_NTXDESC >= 32 && GEM_NTXDESC <= 8192); + #define TRIES 10000 + /* * The GEM hardware support basic TCP/UDP checksum offloading. However, * the hardware doesn't compensate the checksum for UDP datagram which @@ -102,14 +106,16 @@ static int gem_watchdog(struct gem_softc *); static void gem_init(void *); static void gem_init_locked(struct gem_softc *); static void gem_init_regs(struct gem_softc *); -static int gem_ringsize(int sz); +static u_int gem_ringsize(u_int); static int gem_meminit(struct gem_softc *); static struct mbuf *gem_defrag(struct mbuf *, int, int); static int gem_load_txmbuf(struct gem_softc *, struct mbuf **); static void gem_mifinit(struct gem_softc *); static int gem_bitwait(struct gem_softc *, bus_addr_t, u_int32_t, u_int32_t); +static void gem_reset(struct gem_softc *); static int gem_reset_rx(struct gem_softc *); +static void gem_reset_rxdma(struct gem_softc *sc); static int gem_reset_tx(struct gem_softc *); static int gem_disable_rx(struct gem_softc *); static int gem_disable_tx(struct gem_softc *); @@ -124,9 +130,6 @@ static void gem_rint(struct gem_softc *); static void gem_rint_timeout(void *); #endif static void gem_tint(struct gem_softc *); -#ifdef notyet -static void gem_power(int, void *); -#endif devclass_t gem_devclass; DRIVER_MODULE(miibus, gem, miibus_driver, miibus_devclass, 0, 0); @@ -149,7 +152,6 @@ gem_attach(sc) struct gem_softc *sc; { struct ifnet *ifp; - struct mii_softc *child; int i, error; u_int32_t v; @@ -164,10 +166,7 @@ gem_attach(sc) /* Make sure the chip is stopped. */ ifp->if_softc = sc; - GEM_LOCK(sc); - gem_stop(ifp, 0); gem_reset(sc); - GEM_UNLOCK(sc); error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, @@ -257,11 +256,73 @@ gem_attach(sc) sc->sc_rxsoft[i].rxs_mbuf = NULL; } + /* Bad things will happen when touching this register on ERI. */ + if (sc->sc_variant != GEM_SUN_ERI) + bus_write_4(sc->sc_res[0], GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_MII); + gem_mifinit(sc); - if ((error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, gem_mediachange, - gem_mediastatus)) != 0) { - device_printf(sc->sc_dev, "phy probe failed: %d\n", error); + /* + * Look for an external PHY. + */ + error = ENXIO; + v = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG); + if ((v & GEM_MIF_CONFIG_MDI1) != 0) { + v |= GEM_MIF_CONFIG_PHY_SEL; + bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v); + switch (sc->sc_variant) { + case GEM_SUN_ERI: + sc->sc_phyad = GEM_PHYAD_EXTERNAL; + break; + default: + sc->sc_phyad = -1; + break; + } + error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, + gem_mediachange, gem_mediastatus); + } + + /* + * Fall back on an internal PHY if no external PHY was found. + */ + if (error != 0 && (v & GEM_MIF_CONFIG_MDI0) != 0) { + v &= ~GEM_MIF_CONFIG_PHY_SEL; + bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v); + switch (sc->sc_variant) { + case GEM_SUN_ERI: + case GEM_APPLE_K2_GMAC: + sc->sc_phyad = GEM_PHYAD_INTERNAL; + break; + case GEM_APPLE_GMAC: + sc->sc_phyad = GEM_PHYAD_EXTERNAL; + break; + default: + sc->sc_phyad = -1; + break; + } + error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, + gem_mediachange, gem_mediastatus); + } + + /* + * Try the external PCS SERDES if we didn't find any PHYs. + */ + if (error != 0 && sc->sc_variant == GEM_SUN_GEM) { + bus_write_4(sc->sc_res[0], GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_SERDES); + bus_write_4(sc->sc_res[0], GEM_MII_SLINK_CONTROL, + GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); + bus_write_4(sc->sc_res[0], GEM_MII_CONFIG, + GEM_MII_CONFIG_ENABLE); + sc->sc_flags |= GEM_SERDES; + sc->sc_phyad = GEM_PHYAD_EXTERNAL; + error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, + gem_mediachange, gem_mediastatus); + } + + if (error != 0) { + device_printf(sc->sc_dev, "PHY probe failed: %d\n", error); goto fail_rxd; } sc->sc_mii = device_get_softc(sc->sc_miibus); @@ -293,64 +354,10 @@ gem_attach(sc) IFQ_SET_MAXLEN(&ifp->if_snd, GEM_TXQUEUELEN); ifp->if_snd.ifq_drv_maxlen = GEM_TXQUEUELEN; IFQ_SET_READY(&ifp->if_snd); - /* - * 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 = LIST_FIRST(&sc->sc_mii->mii_phys); 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) { - device_printf(sc->sc_dev, "cannot accomodate " - "MII device %s at phy %d, instance %d\n", - device_get_name(child->mii_dev), - 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 - printf("using external phy\n"); -#endif - sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL; - } else { -#ifdef GEM_DEBUG - printf("using internal phy\n"); -#endif - sc->sc_mif_config &= ~GEM_MIF_CONFIG_PHY_SEL; - } - bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, - sc->sc_mif_config); /* Attach the interface. */ ether_ifattach(ifp, sc->sc_enaddr); -#ifdef notyet - /* - * Add a suspend hook to make sure we come back up after a - * resume. - */ - sc->sc_powerhook = powerhook_establish(gem_power, sc); - if (sc->sc_powerhook == NULL) - device_printf(sc->sc_dev, "WARNING: unable to establish power " - "hook\n"); -#endif - /* * Tell the upper layer(s) we support long frames/checksum offloads. */ @@ -455,7 +462,7 @@ gem_resume(sc) * On resume all registers have to be initialized again like * after power-on. */ - sc->sc_inited = 0; + sc->sc_flags &= ~GEM_INITED; if (ifp->if_flags & IFF_UP) gem_init_locked(sc); GEM_UNLOCK(sc); @@ -580,7 +587,7 @@ gem_cddma_callback(xsc, segs, nsegs, error) return; if (nsegs != 1) { /* can't happen... */ - panic("gem_cddma_callback: bad control buffer segment count"); + panic("%s: bad control buffer segment count", __func__); } sc->sc_cddma = segs[0].ds_addr; } @@ -638,7 +645,7 @@ gem_bitwait(sc, r, clr, set) return (0); } -void +static void gem_reset(sc) struct gem_softc *sc; { @@ -651,11 +658,11 @@ gem_reset(sc) /* Do a full reset */ bus_write_4(sc->sc_res[0], GEM_RESET, GEM_RESET_RX | GEM_RESET_TX); + bus_barrier(sc->sc_res[0], GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE); if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0)) device_printf(sc->sc_dev, "cannot reset device\n"); } - /* * gem_rxdrain: * @@ -698,7 +705,7 @@ gem_stop(ifp, disable) callout_stop(&sc->sc_tick_ch); #ifdef GEM_RINT_TIMEOUT callout_stop(&sc->sc_rx_ch); -#endif +#endif /* XXX - Should we reset these instead? */ gem_disable_tx(sc); @@ -728,13 +735,14 @@ gem_stop(ifp, disable) * Mark the interface down and cancel the watchdog timer. */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + sc->sc_flags &= ~GEM_LINK; sc->sc_wdog_timer = 0; } /* * Reset the receiver */ -int +static int gem_reset_rx(sc) struct gem_softc *sc; { @@ -745,23 +753,62 @@ gem_reset_rx(sc) */ gem_disable_rx(sc); bus_write_4(sc->sc_res[0], GEM_RX_CONFIG, 0); - /* Wait till it finishes */ - if (!gem_bitwait(sc, GEM_RX_CONFIG, 1, 0)) - device_printf(sc->sc_dev, "cannot disable read dma\n"); - - /* Wait 5ms extra. */ - DELAY(5000); + bus_barrier(sc->sc_res[0], GEM_RX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_RX_CONFIG, GEM_RX_CONFIG_RXDMA_EN, 0)) + device_printf(sc->sc_dev, "cannot disable RX DMA\n"); /* Finally, reset the ERX */ bus_write_4(sc->sc_res[0], GEM_RESET, GEM_RESET_RX); - /* Wait till it finishes */ - if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_RX, 0)) { + bus_barrier(sc->sc_res[0], GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0)) { device_printf(sc->sc_dev, "cannot reset receiver\n"); return (1); } return (0); } +/* + * 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) +{ + int i; + + if (gem_reset_rx(sc) != 0) + return (gem_init_locked(sc)); + 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); + + /* NOTE: we use only 32-bit DMA addresses here. */ + bus_write_4(sc->sc_res[0], GEM_RX_RING_PTR_HI, 0); + bus_write_4(sc->sc_res[0], GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); + bus_write_4(sc->sc_res[0], GEM_RX_KICK, GEM_NRXDESC - 4); + bus_write_4(sc->sc_res[0], GEM_RX_CONFIG, + gem_ringsize(GEM_NRXDESC /*XXX*/) | + ((ETHER_HDR_LEN + sizeof(struct ip)) << + GEM_RX_CONFIG_CXM_START_SHFT) | + (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) | + (2 << GEM_RX_CONFIG_FBOFF_SHFT)); + bus_write_4(sc->sc_res[0], GEM_RX_BLANKING, + (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6); + bus_write_4(sc->sc_res[0], GEM_RX_PAUSE_THRESH, + (3 * sc->sc_rxfifosize / 256) | ((sc->sc_rxfifosize / 256) << 12)); + bus_write_4(sc->sc_res[0], GEM_RX_CONFIG, + bus_read_4(sc->sc_res[0], GEM_RX_CONFIG) | GEM_RX_CONFIG_RXDMA_EN); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_MASK, + GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, + bus_read_4(sc->sc_res[0], GEM_MAC_RX_CONFIG) | GEM_MAC_RX_ENABLE); +} /* * Reset the transmitter @@ -770,7 +817,6 @@ static int gem_reset_tx(sc) struct gem_softc *sc; { - int i; /* * Resetting while DMA is in progress can cause a bus hang, so we @@ -778,21 +824,15 @@ gem_reset_tx(sc) */ gem_disable_tx(sc); bus_write_4(sc->sc_res[0], GEM_TX_CONFIG, 0); - /* Wait till it finishes */ - if (!gem_bitwait(sc, GEM_TX_CONFIG, 1, 0)) - device_printf(sc->sc_dev, "cannot disable read dma\n"); - - /* Wait 5ms extra. */ - DELAY(5000); + bus_barrier(sc->sc_res[0], GEM_TX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_TX_CONFIG, GEM_TX_CONFIG_TXDMA_EN, 0)) + device_printf(sc->sc_dev, "cannot disable TX DMA\n"); /* Finally, reset the ETX */ bus_write_4(sc->sc_res[0], GEM_RESET, GEM_RESET_TX); - /* Wait till it finishes */ - for (i = TRIES; i--; DELAY(100)) - if ((bus_read_4(sc->sc_res[0], GEM_RESET) & GEM_RESET_TX) == 0) - break; - if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_TX, 0)) { - device_printf(sc->sc_dev, "cannot reset receiver\n"); + bus_barrier(sc->sc_res[0], GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0)) { + device_printf(sc->sc_dev, "cannot reset transmitter\n"); return (1); } return (0); @@ -811,8 +851,8 @@ gem_disable_rx(sc) cfg = bus_read_4(sc->sc_res[0], GEM_MAC_RX_CONFIG); cfg &= ~GEM_MAC_RX_ENABLE; bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, cfg); - - /* Wait for it to finish */ + bus_barrier(sc->sc_res[0], GEM_MAC_RX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); return (gem_bitwait(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)); } @@ -829,8 +869,8 @@ gem_disable_tx(sc) cfg = bus_read_4(sc->sc_res[0], GEM_MAC_TX_CONFIG); cfg &= ~GEM_MAC_TX_ENABLE; bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, cfg); - - /* Wait for it to finish */ + bus_barrier(sc->sc_res[0], GEM_MAC_TX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); return (gem_bitwait(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)); } @@ -883,45 +923,34 @@ gem_meminit(sc) return (0); } -static int +static u_int gem_ringsize(sz) - int sz; + u_int sz; { - int v = 0; switch (sz) { case 32: - v = GEM_RING_SZ_32; - break; + return (GEM_RING_SZ_32); case 64: - v = GEM_RING_SZ_64; - break; + return (GEM_RING_SZ_64); case 128: - v = GEM_RING_SZ_128; - break; + return (GEM_RING_SZ_128); case 256: - v = GEM_RING_SZ_256; - break; + return (GEM_RING_SZ_256); case 512: - v = GEM_RING_SZ_512; - break; + return (GEM_RING_SZ_512); case 1024: - v = GEM_RING_SZ_1024; - break; + return (GEM_RING_SZ_1024); case 2048: - v = GEM_RING_SZ_2048; - break; + return (GEM_RING_SZ_2048); case 4096: - v = GEM_RING_SZ_4096; - break; + return (GEM_RING_SZ_4096); case 8192: - v = GEM_RING_SZ_8192; - break; + return (GEM_RING_SZ_8192); default: - printf("gem: invalid Receive Descriptor ring size\n"); - break; + printf("%s: invalid ring size %d\n", __func__, sz); + return (GEM_RING_SZ_32); } - return (v); } static void @@ -971,7 +1000,8 @@ gem_init_locked(sc) gem_mifinit(sc); /* step 3. Setup data structures in host memory */ - gem_meminit(sc); + if (gem_meminit(sc) != 0) + return; /* step 4. TX MAC registers & counters */ gem_init_regs(sc); @@ -993,16 +1023,24 @@ gem_init_locked(sc) /* step 8. Global Configuration & Interrupt Mask */ bus_write_4(sc->sc_res[0], 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_RX_DONE | + GEM_INTR_RX_NOBUF | GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR | + GEM_INTR_BERR +#ifdef GEM_DEBUG + | GEM_INTR_PCS | GEM_INTR_MIF +#endif + )); bus_write_4(sc->sc_res[0], GEM_MAC_RX_MASK, - GEM_MAC_RX_DONE|GEM_MAC_RX_FRAME_CNT); - bus_write_4(sc->sc_res[0], GEM_MAC_TX_MASK, 0xffff); /* XXXX */ - bus_write_4(sc->sc_res[0], GEM_MAC_CONTROL_MASK, 0); /* XXXX */ + GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); + bus_write_4(sc->sc_res[0], GEM_MAC_TX_MASK, + GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP); +#ifdef GEM_DEBUG + bus_write_4(sc->sc_res[0], GEM_MAC_CONTROL_MASK, + ~(GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME)); +#else + bus_write_4(sc->sc_res[0], GEM_MAC_CONTROL_MASK, + GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME); +#endif /* step 9. ETX Configuration: use mostly default values */ @@ -1014,7 +1052,7 @@ gem_init_locked(sc) /* step 10. ERX Configuration */ - /* Encode Receive Descriptor ring size: four possible values */ + /* Encode Receive Descriptor ring size. */ v = gem_ringsize(GEM_NRXDESC /*XXX*/); /* Rx TCP/UDP checksum offset */ v |= ((ETHER_HDR_LEN + sizeof(struct ip)) << @@ -1024,6 +1062,10 @@ gem_init_locked(sc) bus_write_4(sc->sc_res[0], GEM_RX_CONFIG, v|(GEM_THRSH_1024<<GEM_RX_CONFIG_FIFO_THRS_SHIFT)| (2<<GEM_RX_CONFIG_FBOFF_SHFT)|GEM_RX_CONFIG_RXDMA_EN); + + bus_write_4(sc->sc_res[0], GEM_RX_BLANKING, + (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6); + /* * The following value is for an OFF Threshold of about 3/4 full * and an ON Threshold of 1/4 full. @@ -1031,14 +1073,17 @@ gem_init_locked(sc) bus_write_4(sc->sc_res[0], GEM_RX_PAUSE_THRESH, (3 * sc->sc_rxfifosize / 256) | ( (sc->sc_rxfifosize / 256) << 12)); - bus_write_4(sc->sc_res[0], GEM_RX_BLANKING, (6<<12)|6); /* step 11. Configure Media */ - mii_mediachg(sc->sc_mii); /* step 12. RX_MAC Configuration Register */ v = bus_read_4(sc->sc_res[0], GEM_MAC_RX_CONFIG); - v |= GEM_MAC_RX_ENABLE | GEM_MAC_RX_STRIP_CRC; + v |= GEM_MAC_RX_STRIP_CRC; + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, 0); + bus_barrier(sc->sc_res[0], GEM_MAC_RX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) + device_printf(sc->sc_dev, "cannot disable RX MAC\n"); bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, v); /* step 14. Issue Transmit Pending command */ @@ -1046,13 +1091,16 @@ gem_init_locked(sc) /* step 15. Give the reciever a swift kick */ bus_write_4(sc->sc_res[0], GEM_RX_KICK, GEM_NRXDESC-4); - /* Start the one second timer. */ - sc->sc_wdog_timer = 0; - callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); - ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_ifflags = ifp->if_flags; + + sc->sc_flags &= ~GEM_LINK; + mii_mediachg(sc->sc_mii); + + /* Start the one second timer. */ + sc->sc_wdog_timer = 0; + callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); } /* @@ -1205,7 +1253,7 @@ gem_load_txmbuf(sc, m_head) txs->txs_firstdesc = sc->sc_txnext; nexttx = txs->txs_firstdesc; for (seg = 0; seg < nsegs; seg++, nexttx = GEM_NEXTTX(nexttx)) { -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG CTR6(KTR_GEM, "%s: mapping seg %d (txd %d), len " "%lx, addr %#lx (%#lx)", __func__, seg, nexttx, txsegs[seg].ds_len, txsegs[seg].ds_addr, @@ -1222,7 +1270,7 @@ gem_load_txmbuf(sc, m_head) } /* set EOP on the last descriptor */ -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG CTR3(KTR_GEM, "%s: end of packet at seg %d, tx %d", __func__, seg, nexttx); #endif @@ -1230,7 +1278,7 @@ gem_load_txmbuf(sc, m_head) GEM_DMA_WRITE(sc, GEM_TD_END_OF_PACKET); /* Lastly set SOP on the first descriptor */ -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG CTR3(KTR_GEM, "%s: start of packet at seg %d, tx %d", __func__, seg, nexttx); #endif @@ -1266,11 +1314,9 @@ gem_init_regs(sc) struct gem_softc *sc; { const u_char *laddr = IF_LLADDR(sc->sc_ifp); - u_int32_t v; /* These regs are not cleared on reset */ - if (!sc->sc_inited) { - + if ((sc->sc_flags & GEM_INITED) == 0) { /* Wooo. Magic values. */ bus_write_4(sc->sc_res[0], GEM_MAC_IPG0, 0); bus_write_4(sc->sc_res[0], GEM_MAC_IPG1, 8); @@ -1279,8 +1325,7 @@ gem_init_regs(sc) bus_write_4(sc->sc_res[0], GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN); /* Max frame and max burst size */ bus_write_4(sc->sc_res[0], GEM_MAC_MAC_MAX_FRAME, - (ETHER_MAX_LEN + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) | - (0x2000 << 16)); + (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) | (0x2000 << 16)); bus_write_4(sc->sc_res[0], GEM_MAC_PREAMBLE_LEN, 0x7); bus_write_4(sc->sc_res[0], GEM_MAC_JAM_SIZE, 0x4); @@ -1308,7 +1353,7 @@ gem_init_regs(sc) bus_write_4(sc->sc_res[0], GEM_MAC_ADR_FLT_MASK1_2, 0); bus_write_4(sc->sc_res[0], GEM_MAC_ADR_FLT_MASK0, 0); - sc->sc_inited = 1; + sc->sc_flags |= GEM_INITED; } /* Counters need to be zeroed */ @@ -1324,12 +1369,20 @@ gem_init_regs(sc) bus_write_4(sc->sc_res[0], GEM_MAC_RX_CRC_ERR_CNT, 0); bus_write_4(sc->sc_res[0], GEM_MAC_RX_CODE_VIOL, 0); - /* Un-pause stuff */ -#if 0 + /* Set XOFF PAUSE time. */ bus_write_4(sc->sc_res[0], GEM_MAC_SEND_PAUSE_CMD, 0x1BF0); -#else - bus_write_4(sc->sc_res[0], 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_write_4(sc->sc_res[0], 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. @@ -1338,17 +1391,8 @@ gem_init_regs(sc) bus_write_4(sc->sc_res[0], GEM_MAC_ADDR1, (laddr[2]<<8)|laddr[3]); bus_write_4(sc->sc_res[0], GEM_MAC_ADDR2, (laddr[0]<<8)|laddr[1]); - /* - * Enable MII outputs. Enable GMII if there is a gigabit PHY. - */ - sc->sc_mif_config = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG); - v = GEM_MAC_XIF_TX_MII_ENA; - if (sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) { - v |= GEM_MAC_XIF_FDPLX_LED; - if (sc->sc_flags & GEM_GIGABIT) - v |= GEM_MAC_XIF_GMII_MODE; - } - bus_write_4(sc->sc_res[0], GEM_MAC_XIF_CONFIG, v); + /* Enable MII outputs. */ + bus_write_4(sc->sc_res[0], GEM_MAC_XIF_CONFIG, GEM_MAC_XIF_TX_MII_ENA); } static void @@ -1368,23 +1412,22 @@ gem_start_locked(ifp) { struct gem_softc *sc = (struct gem_softc *)ifp->if_softc; struct mbuf *m; - int firsttx, ntx = 0, txmfail; + int ntx = 0; if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING) + IFF_DRV_RUNNING || (sc->sc_flags & GEM_LINK) == 0) return; - firsttx = sc->sc_txnext; #ifdef GEM_DEBUG CTR4(KTR_GEM, "%s: %s: txfree %d, txnext %d", - device_get_name(sc->sc_dev), __func__, sc->sc_txfree, firsttx); + device_get_name(sc->sc_dev), __func__, sc->sc_txfree, + sc->sc_txnext); #endif for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->sc_txfree > 1;) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; - txmfail = gem_load_txmbuf(sc, &m); - if (txmfail != 0) { + if (gem_load_txmbuf(sc, &m) != 0) { if (m == NULL) break; ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1393,10 +1436,11 @@ gem_start_locked(ifp) } ntx++; /* Kick the transmitter. */ -#ifdef GEM_DEBUG +#ifdef GEM_DEBUG CTR3(KTR_GEM, "%s: %s: kicking tx %d", device_get_name(sc->sc_dev), __func__, sc->sc_txnext); #endif + GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); bus_write_4(sc->sc_res[0], GEM_TX_KICK, sc->sc_txnext); @@ -1404,11 +1448,9 @@ gem_start_locked(ifp) } if (ntx > 0) { - GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); - #ifdef GEM_DEBUG CTR2(KTR_GEM, "%s: packets enqueued, OWN on %d", - device_get_name(sc->sc_dev), firsttx); + device_get_name(sc->sc_dev), sc->sc_txnext); #endif /* Set a watchdog timer in case the chip flakes out. */ @@ -1432,7 +1474,6 @@ gem_tint(sc) int txlast; int progress = 0; - #ifdef GEM_DEBUG CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__); #endif @@ -1461,7 +1502,7 @@ gem_tint(sc) #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 @@ -1507,15 +1548,13 @@ gem_tint(sc) #ifdef GEM_DEBUG CTR4(KTR_GEM, "%s: GEM_TX_STATE_MACHINE %x " - "GEM_TX_DATA_PTR %llx " - "GEM_TX_COMPLETION %x", - __func__, - bus_space_read_4(sc->sc_res[0], sc->sc_h, GEM_TX_STATE_MACHINE), - ((long long) bus_4(sc->sc_res[0], - GEM_TX_DATA_PTR_HI) << 32) | - bus_read_4(sc->sc_res[0], - GEM_TX_DATA_PTR_LO), - bus_read_4(sc->sc_res[0], GEM_TX_COMPLETION)); + "GEM_TX_DATA_PTR %llx " + "GEM_TX_COMPLETION %x", + __func__, + bus_read_4(sc->sc_res[0], GEM_TX_STATE_MACHINE), + ((long long) bus_read_4(sc->sc_res[0], GEM_TX_DATA_PTR_HI) << 32) | + bus_read_4(sc->sc_res[0], GEM_TX_DATA_PTR_LO), + bus_read_4(sc->sc_res[0], GEM_TX_COMPLETION)); #endif if (progress) { @@ -1557,11 +1596,9 @@ gem_rint(sc) struct gem_softc *sc; { struct ifnet *ifp = sc->sc_ifp; - struct gem_rxsoft *rxs; struct mbuf *m; u_int64_t rxstat; u_int32_t rxcomp; - int i, len, progress = 0; #ifdef GEM_RINT_TIMEOUT callout_stop(&sc->sc_rx_ch); @@ -1581,11 +1618,10 @@ gem_rint(sc) __func__, sc->sc_rxptr, rxcomp); #endif GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD); - for (i = sc->sc_rxptr; i != rxcomp; - i = GEM_NEXTRX(i)) { - rxs = &sc->sc_rxsoft[i]; - - rxstat = GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags); + for (; sc->sc_rxptr != rxcomp;) { + m = sc->sc_rxsoft[sc->sc_rxptr].rxs_mbuf; + rxstat = GEM_DMA_READ(sc, + sc->sc_rxdescs[sc->sc_rxptr].gd_flags); if (rxstat & GEM_RD_OWN) { #ifdef GEM_RINT_TIMEOUT @@ -1600,49 +1636,68 @@ gem_rint(sc) callout_reset(&sc->sc_rx_ch, GEM_RXOWN_TICKS, gem_rint_timeout, sc); #endif - break; + m = NULL; + goto kickit; } - progress++; - ifp->if_ipackets++; - if (rxstat & GEM_RD_BAD_CRC) { ifp->if_ierrors++; device_printf(sc->sc_dev, "receive error: CRC error\n"); - GEM_INIT_RXDESC(sc, i); - continue; + GEM_INIT_RXDESC(sc, sc->sc_rxptr); + m = NULL; + goto kickit; } #ifdef GEM_DEBUG if (ifp->if_flags & IFF_DEBUG) { - printf(" rxsoft %p descriptor %d: ", rxs, i); + printf(" rxsoft %p descriptor %d: ", + &sc->sc_rxsoft[sc->sc_rxptr], sc->sc_rxptr); printf("gd_flags: 0x%016llx\t", (long long) - GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags)); + GEM_DMA_READ(sc, sc->sc_rxdescs[ + sc->sc_rxptr].gd_flags)); printf("gd_addr: 0x%016llx\n", (long long) - GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_addr)); + GEM_DMA_READ(sc, sc->sc_rxdescs[ + sc->sc_rxptr].gd_addr)); } #endif /* - * No errors; receive the packet. - */ - len = GEM_RD_BUFLEN(rxstat); - - /* * Allocate a new mbuf cluster. If that fails, we are * out of memory, and must drop the packet and recycle * the buffer that's already attached to this descriptor. */ - m = rxs->rxs_mbuf; - if (gem_add_rxbuf(sc, i) != 0) { + if (gem_add_rxbuf(sc, sc->sc_rxptr) != 0) { ifp->if_ierrors++; - GEM_INIT_RXDESC(sc, i); + GEM_INIT_RXDESC(sc, sc->sc_rxptr); + m = NULL; + } + +kickit: + /* + * Update the RX kick register. This register has to point + * to the descriptor after the last valid one (before the + * current batch) and must be incremented in multiples of + * 4 (because the DMA engine fetches/updates descriptors + * in batches of 4). + */ + sc->sc_rxptr = GEM_NEXTRX(sc->sc_rxptr); + if ((sc->sc_rxptr % 4) == 0) { + GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); + bus_write_4(sc->sc_res[0], GEM_RX_KICK, + (sc->sc_rxptr + GEM_NRXDESC - 4) & + GEM_NRXDESC_MASK); + } + + if (m == NULL) { + if (rxstat & GEM_RD_OWN) + break; continue; } - m->m_data += 2; /* We're already off by two */ + ifp->if_ipackets++; + m->m_data += 2; /* We're already off by two */ m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = len; + m->m_pkthdr.len = m->m_len = GEM_RD_BUFLEN(rxstat); if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) gem_rxcksum(m, rxstat); @@ -1653,23 +1708,12 @@ gem_rint(sc) GEM_LOCK(sc); } - if (progress) { - GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); - /* Update the receive pointer. */ - if (i == sc->sc_rxptr) { - device_printf(sc->sc_dev, "rint: ring wrap\n"); - } - sc->sc_rxptr = i; - bus_write_4(sc->sc_res[0], GEM_RX_KICK, GEM_PREVRX(i)); - } - #ifdef GEM_DEBUG CTR3(KTR_GEM, "%s: done sc->rxptr %d, complete %d", __func__, sc->sc_rxptr, bus_read_4(sc->sc_res[0], GEM_RX_COMPLETION)); #endif } - /* * gem_add_rxbuf: * @@ -1701,8 +1745,6 @@ gem_add_rxbuf(sc, idx) bus_dmamap_unload(sc->sc_rdmatag, rxs->rxs_dmamap); } - rxs->rxs_mbuf = m; - error = bus_dmamap_load_mbuf_sg(sc->sc_rdmatag, rxs->rxs_dmamap, m, segs, &nsegs, BUS_DMA_NOWAIT); /* If nsegs is wrong then the stack is corrupt. */ @@ -1711,8 +1753,9 @@ gem_add_rxbuf(sc, idx) device_printf(sc->sc_dev, "can't load rx DMA map %d, error = " "%d\n", idx, error); m_freem(m); - return (ENOBUFS); + return (error); } + rxs->rxs_mbuf = m; rxs->rxs_paddr = segs[0].ds_addr; bus_dmamap_sync(sc->sc_rdmatag, rxs->rxs_dmamap, BUS_DMASYNC_PREREAD); @@ -1722,66 +1765,95 @@ gem_add_rxbuf(sc, idx) return (0); } - static void gem_eint(sc, status) struct gem_softc *sc; u_int status; { - if ((status & GEM_INTR_MIF) != 0) { - device_printf(sc->sc_dev, "XXXlink status changed\n"); + sc->sc_ifp->if_ierrors++; + if ((status & GEM_INTR_RX_TAG_ERR) != 0) { + gem_reset_rxdma(sc); return; } - device_printf(sc->sc_dev, "status=%x\n", status); + device_printf(sc->sc_dev, "%s: status=%x\n", __func__, status); } - void gem_intr(v) void *v; { struct gem_softc *sc = (struct gem_softc *)v; - u_int32_t status; + uint32_t status, status2; GEM_LOCK(sc); status = bus_read_4(sc->sc_res[0], GEM_STATUS); + #ifdef GEM_DEBUG CTR4(KTR_GEM, "%s: %s: cplt %x, status %x", device_get_name(sc->sc_dev), __func__, (status>>19), (u_int)status); + + /* + * PCS interrupts must be cleared, otherwise no traffic is passed! + */ + if ((status & GEM_INTR_PCS) != 0) { + status2 = bus_read_4(sc->sc_res[0], GEM_MII_INTERRUP_STATUS) | + bus_read_4(sc->sc_res[0], GEM_MII_INTERRUP_STATUS); + if ((status2 & GEM_MII_INTERRUP_LINK) != 0) + device_printf(sc->sc_dev, + "%s: PCS link status changed\n", __func__); + } + 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) + device_printf(sc->sc_dev, + "%s: PAUSE received (PAUSE time %d slots)\n", + __func__, GEM_MAC_PAUSE_TIME(status2)); + if ((status2 & GEM_MAC_PAUSE) != 0) + device_printf(sc->sc_dev, + "%s: transited to PAUSE state\n", __func__); + if ((status2 & GEM_MAC_RESUME) != 0) + device_printf(sc->sc_dev, + "%s: transited to non-PAUSE state\n", __func__); + } + if ((status & GEM_INTR_MIF) != 0) + device_printf(sc->sc_dev, "%s: MIF interrupt\n", __func__); #endif - if ((status & (GEM_INTR_RX_TAG_ERR | GEM_INTR_BERR)) != 0) + if ((status & + (GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR | GEM_INTR_BERR)) != 0) gem_eint(sc, status); - if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0) - gem_tint(sc); - if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0) gem_rint(sc); - /* We should eventually do more than just print out error stats. */ + if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0) + gem_tint(sc); + if (status & GEM_INTR_TX_MAC) { - int txstat = bus_read_4(sc->sc_res[0], GEM_MAC_TX_STATUS); - if (txstat & ~GEM_MAC_TX_XMIT_DONE) + status2 = bus_read_4(sc->sc_res[0], GEM_MAC_TX_STATUS); + if (status2 & ~(GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP)) device_printf(sc->sc_dev, "MAC tx fault, status %x\n", - txstat); - if (txstat & (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG)) + status2); + if (status2 & (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG)) gem_init_locked(sc); } if (status & GEM_INTR_RX_MAC) { - int rxstat = bus_read_4(sc->sc_res[0], GEM_MAC_RX_STATUS); + status2 = bus_read_4(sc->sc_res[0], GEM_MAC_RX_STATUS); /* - * 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_locked(sc); - else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT)) + if (status2 & GEM_MAC_RX_OVERFLOW) { + sc->sc_ifp->if_ierrors++; + gem_reset_rxdma(sc); + } else if (status2 & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT)) device_printf(sc->sc_dev, "MAC rx fault, status %x\n", - rxstat); + status2); } GEM_UNLOCK(sc); } @@ -1809,7 +1881,10 @@ gem_watchdog(sc) if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) return (0); - device_printf(sc->sc_dev, "device timeout\n"); + if ((sc->sc_flags & GEM_LINK) != 0) + device_printf(sc->sc_dev, "device timeout\n"); + else if (bootverbose) + device_printf(sc->sc_dev, "device timeout (no link)\n"); ++sc->sc_ifp->if_oerrors; /* Try to get more packets going. */ @@ -1826,9 +1901,8 @@ gem_mifinit(sc) { /* Configure the MIF in frame mode */ - sc->sc_mif_config = bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG); - sc->sc_mif_config &= ~GEM_MIF_CONFIG_BB_ENA; - bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, sc->sc_mif_config); + bus_write_4(sc->sc_res[0], GEM_MIF_CONFIG, bus_read_4(sc->sc_res[0], + GEM_MIF_CONFIG) & ~GEM_MIF_CONFIG_BB_ENA); } /* @@ -1855,23 +1929,43 @@ gem_mii_readreg(dev, phy, reg) u_int32_t v; #ifdef GEM_DEBUG_PHY - printf("gem_mii_readreg: phy %d reg %d\n", phy, reg); + printf("%s: phy %d reg %d\n", __func__, phy, reg); #endif -#if 0 - /* Select the desired PHY in the MIF configuration register */ - v = bus_read_4(sc->sc_res[0], 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_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v); -#endif + if (sc->sc_phyad != -1 && phy != sc->sc_phyad) + return (0); + + if ((sc->sc_flags & GEM_SERDES) != 0) { + switch (reg) { + case MII_BMCR: + reg = GEM_MII_CONTROL; + break; + case MII_BMSR: + reg = GEM_MII_STATUS; + break; + case MII_PHYIDR1: + case MII_PHYIDR2: + return (0); + case MII_ANAR: + reg = GEM_MII_ANAR; + break; + case MII_ANLPAR: + reg = GEM_MII_ANLPAR; + break; + case MII_EXTSR: + return (EXTSR_1000XFDX | EXTSR_1000XHDX); + default: + device_printf(sc->sc_dev, + "%s: unhandled register %d\n", __func__, reg); + return (0); + } + return (bus_read_4(sc->sc_res[0], reg)); + } /* Construct the frame command */ - v = (reg << GEM_MIF_REG_SHIFT) | (phy << GEM_MIF_PHY_SHIFT) | - GEM_MIF_FRAME_READ; + v = GEM_MIF_FRAME_READ | + (phy << GEM_MIF_PHY_SHIFT) | + (reg << GEM_MIF_REG_SHIFT); bus_write_4(sc->sc_res[0], GEM_MIF_FRAME, v); for (n = 0; n < 100; n++) { @@ -1895,23 +1989,46 @@ gem_mii_writereg(dev, phy, reg, val) u_int32_t v; #ifdef GEM_DEBUG_PHY - printf("gem_mii_writereg: phy %d reg %d val %x\n", phy, reg, val); + printf("%s: phy %d reg %d val %x\n", phy, reg, val, __func__); #endif -#if 0 - /* Select the desired PHY in the MIF configuration register */ - v = bus_read_4(sc->sc_res[0], 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_write_4(sc->sc_res[0], GEM_MIF_CONFIG, v); -#endif + if (sc->sc_phyad != -1 && phy != sc->sc_phyad) + return (0); + + if ((sc->sc_flags & GEM_SERDES) != 0) { + switch (reg) { + case MII_BMCR: + reg = GEM_MII_CONTROL; + break; + case MII_BMSR: + reg = GEM_MII_STATUS; + break; + case MII_ANAR: + bus_write_4(sc->sc_res[0], GEM_MII_CONFIG, 0); + bus_barrier(sc->sc_res[0], GEM_MII_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + bus_write_4(sc->sc_res[0], GEM_MII_ANAR, val); + bus_write_4(sc->sc_res[0], GEM_MII_SLINK_CONTROL, + GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); + bus_write_4(sc->sc_res[0], GEM_MII_CONFIG, + GEM_MII_CONFIG_ENABLE); + return (0); + case MII_ANLPAR: + reg = GEM_MII_ANLPAR; + break; + default: + device_printf(sc->sc_dev, + "%s: unhandled register %d\n", __func__, reg); + return (0); + } + bus_write_4(sc->sc_res[0], reg, val); + return (0); + } + /* Construct the frame command */ - v = GEM_MIF_FRAME_WRITE | - (phy << GEM_MIF_PHY_SHIFT) | - (reg << GEM_MIF_REG_SHIFT) | + v = GEM_MIF_FRAME_WRITE | + (phy << GEM_MIF_PHY_SHIFT) | + (reg << GEM_MIF_REG_SHIFT) | (val & GEM_MIF_FRAME_DATA); bus_write_4(sc->sc_res[0], GEM_MIF_FRAME, v); @@ -1931,52 +2048,109 @@ gem_mii_statchg(dev) device_t dev; { struct gem_softc *sc = device_get_softc(dev); -#ifdef GEM_DEBUG - int instance; -#endif - u_int32_t v; + int gigabit; + uint32_t rxcfg, txcfg, v; #ifdef GEM_DEBUG - instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media); - if (sc->sc_debug) - printf("gem_mii_statchg: status change: phy = %d\n", - sc->sc_phys[instance]); + if ((sc->sc_ifflags & IFF_DEBUG) != 0) + device_printf(sc->sc_dev, "%s: status change: PHY = %d\n", + __func__, sc->sc_phyad); #endif - /* Set tx full duplex options */ - bus_write_4(sc->sc_res[0], 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_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, v); + + /* + * 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. + */ + + rxcfg = bus_read_4(sc->sc_res[0], 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 != 0) { + rxcfg |= GEM_MAC_RX_CARR_EXTEND; + txcfg |= GEM_MAC_TX_CARR_EXTEND; + } + bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, 0); + bus_barrier(sc->sc_res[0], GEM_MAC_TX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) + device_printf(sc->sc_dev, "cannot disable TX MAC\n"); + bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, txcfg); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, 0); + bus_barrier(sc->sc_res[0], GEM_MAC_RX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) + device_printf(sc->sc_dev, "cannot disable RX MAC\n"); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, rxcfg); + + v = bus_read_4(sc->sc_res[0], GEM_MAC_CONTROL_CONFIG) & + ~(GEM_MAC_CC_RX_PAUSE | GEM_MAC_CC_TX_PAUSE); +#ifdef notyet + if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) + v |= GEM_MAC_CC_RX_PAUSE; + if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) + v |= GEM_MAC_CC_TX_PAUSE; +#endif + bus_write_4(sc->sc_res[0], GEM_MAC_CONTROL_CONFIG, v); + + if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0 && + gigabit != 0) + bus_write_4(sc->sc_res[0], GEM_MAC_SLOT_TIME, + GEM_MAC_SLOT_TIME_CARR_EXTEND); + else + bus_write_4(sc->sc_res[0], GEM_MAC_SLOT_TIME, + GEM_MAC_SLOT_TIME_NORMAL); /* XIF Configuration */ 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_read_4(sc->sc_res[0], 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; + if ((sc->sc_flags & GEM_SERDES) == 0) { + if ((bus_read_4(sc->sc_res[0], GEM_MIF_CONFIG) & + GEM_MIF_CONFIG_PHY_SEL) != 0 && + (IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0) + /* External MII needs echo disable if half duplex. */ + v |= GEM_MAC_XIF_ECHO_DISABL; else - /* half duplex -- disable echo */ - v |= GEM_MAC_XIF_ECHO_DISABL; - - if (IFM_SUBTYPE(sc->sc_mii->mii_media_active) == IFM_1000_T) - 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; + /* + * Internal MII needs buffer enable. + * XXX buffer enable makes only sense for an + * external PHY. + */ + v |= GEM_MAC_XIF_MII_BUF_ENA; } + if (gigabit != 0) + v |= GEM_MAC_XIF_GMII_MODE; + if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0) + v |= GEM_MAC_XIF_FDPLX_LED; bus_write_4(sc->sc_res[0], GEM_MAC_XIF_CONFIG, v); + + if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + (sc->sc_flags & GEM_LINK) != 0) { + bus_write_4(sc->sc_res[0], GEM_MAC_TX_CONFIG, + txcfg | GEM_MAC_TX_ENABLE); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, + rxcfg | GEM_MAC_RX_ENABLE); + } } int @@ -2030,7 +2204,9 @@ gem_ioctl(ifp, cmd, data) case SIOCSIFFLAGS: GEM_LOCK(sc); if (ifp->if_flags & IFF_UP) { - if ((sc->sc_ifflags ^ ifp->if_flags) == IFF_PROMISC) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + ((ifp->if_flags ^ sc->sc_ifflags) & + (IFF_ALLMULTI | IFF_PROMISC)) != 0) gem_setladrf(sc); else gem_init_locked(sc); @@ -2101,14 +2277,17 @@ gem_setladrf(sc) v &= ~(GEM_MAC_RX_PROMISCUOUS|GEM_MAC_RX_HASH_FILTER| GEM_MAC_RX_PROMISC_GRP); + bus_write_4(sc->sc_res[0], GEM_MAC_RX_CONFIG, v); + bus_barrier(sc->sc_res[0], GEM_MAC_RX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_HASH_FILTER, 0)) + device_printf(sc->sc_dev, "cannot disable RX hash filter\n"); + if ((ifp->if_flags & IFF_PROMISC) != 0) { - /* Turn on promiscuous mode */ v |= GEM_MAC_RX_PROMISCUOUS; goto chipit; } if ((ifp->if_flags & IFF_ALLMULTI) != 0) { - hash[3] = hash[2] = hash[1] = hash[0] = 0xffff; - ifp->if_flags |= IFF_ALLMULTI; v |= GEM_MAC_RX_PROMISC_GRP; goto chipit; } @@ -2140,7 +2319,6 @@ gem_setladrf(sc) IF_ADDR_UNLOCK(ifp); v |= GEM_MAC_RX_HASH_FILTER; - ifp->if_flags &= ~IFF_ALLMULTI; /* Now load the hash table into the chip (if we are using it) */ for (i = 0; i < 16; i++) { diff --git a/sys/dev/gem/if_gem_pci.c b/sys/dev/gem/if_gem_pci.c index 77f89cf..742bf8f 100644 --- a/sys/dev/gem/if_gem_pci.c +++ b/sys/dev/gem/if_gem_pci.c @@ -25,50 +25,41 @@ * SUCH DAMAGE. * * from: NetBSD: if_gem_pci.c,v 1.7 2001/10/18 15:09:15 thorpej Exp - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); /* - * PCI bindings for Sun GEM ethernet controllers. + * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers */ #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> -#include <sys/malloc.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/resource.h> +#include <sys/rman.h> #include <sys/socket.h> -#include <machine/endian.h> - #include <net/ethernet.h> #include <net/if.h> -#include <net/if_arp.h> -#include <net/if_dl.h> -#include <net/if_media.h> #include <machine/bus.h> -#include <machine/resource.h> +#if defined(__powerpc__) || defined(__sparc64__) #include <dev/ofw/openfirm.h> #include <machine/ofw_machdep.h> - -#include <sys/rman.h> - -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> +#endif +#include <machine/resource.h> #include <dev/gem/if_gemreg.h> #include <dev/gem/if_gemvar.h> -#include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> #include "miibus_if.h" @@ -106,41 +97,35 @@ static driver_t gem_pci_driver = { sizeof(struct gem_softc) }; - DRIVER_MODULE(gem, pci, gem_pci_driver, gem_devclass, 0, 0); MODULE_DEPEND(gem, pci, 1, 1, 1); MODULE_DEPEND(gem, ether, 1, 1, 1); -struct gem_pci_dev { - u_int32_t gpd_devid; - int gpd_variant; - char *gpd_desc; +static const struct gem_pci_dev { + uint32_t gpd_devid; + int gpd_variant; + const char *gpd_desc; } gem_pci_devlist[] = { - { 0x1101108e, GEM_SUN_GEM, "Sun ERI 10/100 Ethernet Adaptor" }, - { 0x2bad108e, GEM_SUN_GEM, "Sun GEM Gigabit Ethernet Adaptor" }, - { 0x0021106b, GEM_APPLE_GMAC, "Apple GMAC Ethernet Adaptor" }, - { 0x0024106b, GEM_APPLE_GMAC, "Apple GMAC2 Ethernet Adaptor" }, - { 0x0032106b, GEM_APPLE_GMAC, "Apple GMAC3 Ethernet Adaptor" }, + { 0x1101108e, GEM_SUN_ERI, "Sun ERI 10/100 Ethernet" }, + { 0x2bad108e, GEM_SUN_GEM, "Sun GEM Gigabit Ethernet" }, + { 0x0021106b, GEM_APPLE_GMAC, "Apple UniNorth GMAC Ethernet" }, + { 0x0024106b, GEM_APPLE_GMAC, "Apple Pangea GMAC Ethernet" }, + { 0x0032106b, GEM_APPLE_GMAC, "Apple UniNorth2 GMAC Ethernet" }, + { 0x004c106b, GEM_APPLE_K2_GMAC,"Apple K2 GMAC Ethernet" }, + { 0x0051106b, GEM_APPLE_GMAC, "Apple Shasta GMAC Ethernet" }, + { 0x006b106b, GEM_APPLE_GMAC, "Apple Intrepid 2 GMAC Ethernet" }, { 0, 0, NULL } }; -/* - * Attach routines need to be split out to different bus-specific files. - */ static int gem_pci_probe(dev) device_t dev; { int i; - u_int32_t devid; - struct gem_softc *sc; - devid = pci_get_devid(dev); for (i = 0; gem_pci_devlist[i].gpd_desc != NULL; i++) { - if (devid == gem_pci_devlist[i].gpd_devid) { + if (pci_get_devid(dev) == gem_pci_devlist[i].gpd_devid) { device_set_desc(dev, gem_pci_devlist[i].gpd_desc); - sc = device_get_softc(dev); - sc->sc_variant = gem_pci_devlist[i].gpd_variant; return (BUS_PROBE_DEFAULT); } } @@ -149,7 +134,7 @@ gem_pci_probe(dev) } static struct resource_spec gem_pci_res_spec[] = { - { SYS_RES_MEMORY, PCI_GEM_BASEADDR, RF_ACTIVE }, + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE }, { -1, 0 } }; @@ -158,7 +143,24 @@ static int gem_pci_attach(dev) device_t dev; { - struct gem_softc *sc = device_get_softc(dev); + struct gem_softc *sc; + int i; +#if !(defined(__powerpc__) || defined(__sparc64__)) + int j; +#endif + + sc = device_get_softc(dev); + sc->sc_variant = GEM_UNKNOWN; + for (i = 0; gem_pci_devlist[i].gpd_desc != NULL; i++) { + if (pci_get_devid(dev) == gem_pci_devlist[i].gpd_devid) { + sc->sc_variant = gem_pci_devlist[i].gpd_variant; + break; + } + } + if (sc->sc_variant == GEM_UNKNOWN) { + device_printf(dev, "unknown adaptor\n"); + return (ENXIO); + } pci_enable_busmaster(dev); @@ -170,7 +172,7 @@ gem_pci_attach(dev) pci_set_intpin(dev, 1); sc->sc_dev = dev; - sc->sc_pci = 1; /* XXX */ + sc->sc_flags |= GEM_PCI; /* XXX */ if (bus_alloc_resources(dev, gem_pci_res_spec, sc->sc_res)) { device_printf(dev, "failed to allocate resources\n"); @@ -180,8 +182,93 @@ gem_pci_attach(dev) GEM_LOCK_INIT(sc, device_get_nameunit(dev)); - /* All platform that this driver is used on must provide this. */ +#if defined(__powerpc__) || defined(__sparc64__) OF_getetheraddr(dev, sc->sc_enaddr); +#else + /* + * Dig out VPD (vital product data) and read NA (network address). + * The VPD of GEM resides in the PCI Expansion ROM (PCI FCode) and + * can't be accessed via the PCI capability pointer. + * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) + * chapter 2 describes the data structure. + */ + +#define PCI_ROMHDR_SIZE 0x1c +#define PCI_ROMHDR_SIG 0x00 +#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */ +#define PCI_ROMHDR_PTR_DATA 0x18 +#define PCI_ROM_SIZE 0x18 +#define PCI_ROM_SIG 0x00 +#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */ + /* reversed */ +#define PCI_ROM_VENDOR 0x04 +#define PCI_ROM_DEVICE 0x06 +#define PCI_ROM_PTR_VPD 0x08 +#define PCI_VPDRES_BYTE0 0x00 +#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) +#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) +#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ +#define PCI_VPDRES_LARGE_LEN_LSB 0x01 +#define PCI_VPDRES_LARGE_LEN_MSB 0x02 +#define PCI_VPDRES_LARGE_DATA 0x03 +#define PCI_VPD_SIZE 0x03 +#define PCI_VPD_KEY0 0x00 +#define PCI_VPD_KEY1 0x01 +#define PCI_VPD_LEN 0x02 +#define PCI_VPD_DATA 0x03 + +#define GEM_ROM_READ_N(n, sc, offs) \ + bus_read_ ## n ((sc)->sc_res[0], GEM_PCI_ROM_OFFSET + (offs)) +#define GEM_ROM_READ_1(sc, offs) GEM_ROM_READ_N(1, (sc), (offs)) +#define GEM_ROM_READ_2(sc, offs) GEM_ROM_READ_N(2, (sc), (offs)) +#define GEM_ROM_READ_4(sc, offs) GEM_ROM_READ_N(4, (sc), (offs)) + + /* Read PCI Expansion ROM header. */ + if (GEM_ROM_READ_2(sc, PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC || + (i = GEM_ROM_READ_2(sc, PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) { + device_printf(dev, "unexpected PCI Expansion ROM header\n"); + goto fail; + } + + /* Read PCI Expansion ROM data. */ + if (GEM_ROM_READ_4(sc, i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC || + GEM_ROM_READ_2(sc, i + PCI_ROM_VENDOR) != pci_get_vendor(dev) || + GEM_ROM_READ_2(sc, i + PCI_ROM_DEVICE) != pci_get_device(dev) || + (j = GEM_ROM_READ_2(sc, i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) { + device_printf(dev, "unexpected PCI Expansion ROM data\n"); + goto fail; + } + + /* + * Read PCI VPD. + * SUNW,pci-gem cards have a single large resource VPD-R tag + * containing one NA. The VPD used is not in PCI 2.2 standard + * format however. The length in the resource header is in big + * endian and the end tag is non-standard (0x79) and followed + * by an all-zero "checksum" byte. Sun calls this a "Fresh + * Choice Ethernet" VPD... + */ + if (PCI_VPDRES_ISLARGE(GEM_ROM_READ_1(sc, j + PCI_VPDRES_BYTE0)) == 0 || + PCI_VPDRES_LARGE_NAME(GEM_ROM_READ_1(sc, j + PCI_VPDRES_BYTE0)) != + PCI_VPDRES_TYPE_VPD || + (GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_LSB) << 8 | + GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_MSB)) != + PCI_VPD_SIZE + ETHER_ADDR_LEN || + GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) != + 0x4e /* N */ || + GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) != + 0x41 /* A */ || + GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) != + ETHER_ADDR_LEN || + GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA + + ETHER_ADDR_LEN) != 0x79) { + device_printf(dev, "unexpected PCI VPD\n"); + goto fail; + } + bus_read_region_1(sc->sc_res[0], GEM_PCI_ROM_OFFSET + j + + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA, sc->sc_enaddr, + ETHER_ADDR_LEN); +#endif /* * call the main configure @@ -200,8 +287,8 @@ gem_pci_attach(dev) return (0); fail: - bus_release_resources(dev, gem_pci_res_spec, sc->sc_res); GEM_LOCK_DESTROY(sc); + bus_release_resources(dev, gem_pci_res_spec, sc->sc_res); return (ENXIO); } diff --git a/sys/dev/gem/if_gemreg.h b/sys/dev/gem/if_gemreg.h index 24924cf..4c060c9 100644 --- a/sys/dev/gem/if_gemreg.h +++ b/sys/dev/gem/if_gemreg.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: NetBSD: gemreg.h,v 1.15 2002/05/11 00:36:02 matt Exp + * from: NetBSD: gemreg.h,v 1.8 2005/12/11 12:21:26 christos Exp * * $FreeBSD$ */ @@ -55,10 +55,15 @@ /* Bits in GEM_CONFIG register */ -#define GEM_CONFIG_BURST_64 0x000000000 /* 0->infininte, 1->64KB */ -#define GEM_CONFIG_BURST_INF 0x000000001 /* 0->infininte, 1->64KB */ +#define GEM_CONFIG_BURST_64 0x000000000 /* maximum burst size 64KB */ +#define GEM_CONFIG_BURST_INF 0x000000001 /* infinite for entire packet */ #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 @@ -68,31 +73,35 @@ #define GEM_STATUS_TX_COMPL 0xfff800000 /* TX completion reg. */ -/* Interrupt bits, for both the GEM_STATUS and GEM_INTMASK regs. */ +/* + * Interrupt bits, for both the GEM_STATUS and GEM_INTMASK regs. + * Bits 0-6 auto-clear when read. + */ #define GEM_INTR_TX_INTME 0x000000001 /* Frame w/INTME bit set sent */ #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 +#define GEM_INTR_PERR 0x000000080 /* Parity error */ +#define GEM_INTR_PCS 0x000002000 /* Physical Code Sub-layer */ #define GEM_INTR_TX_MAC 0x000004000 #define GEM_INTR_RX_MAC 0x000008000 #define GEM_INTR_MAC_CONTROL 0x000010000 /* MAC control interrupt */ #define GEM_INTR_MIF 0x000020000 #define GEM_INTR_BERR 0x000040000 /* Bus error interrupt */ -#define GEM_INTR_BITS "\177\020" \ +#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" /* GEM_ERROR_STATUS and GEM_ERROR_MASK PCI error bits */ #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 */ @@ -100,6 +109,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. */ @@ -188,7 +199,7 @@ #define GEM_RX_CONFIG_RXRING_SZ 0x0000001e /* RX ring size */ #define GEM_RX_CONFIG_BATCH_DIS 0x00000020 /* desc batching disable */ #define GEM_RX_CONFIG_FBOFF 0x00001c00 /* first byte offset */ -#define GEM_RX_CONFIG_CXM_START 0x000fe000 /* checksum start offset */ +#define GEM_RX_CONFIG_CXM_START 0x000fe000 /* cksum start offset bytes */ #define GEM_RX_CONFIG_FIFO_THRS 0x07000000 /* fifo threshold size */ #define GEM_THRSH_64 0 @@ -232,7 +243,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 @@ -285,7 +296,7 @@ #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_MAC_STATE 0x6134 /* MAC state machine reg */ /* GEM_MAC_SEND_PAUSE_CMD register bits */ @@ -319,7 +330,12 @@ #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_SLTS 0xffff0000 /* pause time in slots */ +#define GEM_MAC_STATUS_BITS "\177\020b\0PAUSED\0b\1PAUSE\0b\2RESUME\0\0" + +#define GEM_MAC_PAUSE_TIME_SHFT 16 +#define GEM_MAC_PAUSE_TIME(x) \ + (((x) & GEM_MAC_PAUSE_TIME_SLTS) >> GEM_MAC_PAUSE_TIME_SHFT) /* GEM_MAC_XIF_CONFIG register bits */ #define GEM_MAC_XIF_TX_MII_ENA 0x00000001 /* Enable XIF output drivers */ @@ -329,11 +345,22 @@ #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 + * 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 /* GEM_MAC_TX_CONFIG register bits */ #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 collitions */ +#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 */ @@ -342,6 +369,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 */ @@ -358,12 +390,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 */ @@ -395,14 +432,16 @@ /* 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 */ #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_PHY_ADR 0x00007c00 /* poll PHY address */ -/* MDI0 is onboard tranciever MID1 is external, PHYAD for both is 0 */ +/* MDI0 is onboard transceiver MDI1 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 */ @@ -416,47 +455,52 @@ */ -/* 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 #define GEM_MII_SLINK_STATUS 0x905c /* serial link status */ -/* GEM_MII_CONTROL bits */ -/* - * DO NOT TOUCH THIS REGISTER ON ERI -- IT HARD HANGS. - */ +/* 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 negotioation */ +#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 */ +/* 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 */ #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_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 */ +/* 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 */ @@ -465,27 +509,59 @@ #define GEM_MII_ANEG_SYM_PAUSE 0x00000080 /* symmetric pause */ #define GEM_MII_ANEG_HLF_DUPLX 0x00000040 #define GEM_MII_ANEG_FUL_DUPLX 0x00000020 +#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 */ -#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" + + +/* + * GEM_MII_STATE_MACHINE + * XXX These are best guesses from observed behavior. + */ +#define GEM_MII_FSM_STOP 0x00000000 /* stopped */ +#define GEM_MII_FSM_RUN 0x00000001 /* running */ +#define GEM_MII_FSM_UNKWN 0x00000100 /* unknown */ +#define GEM_MII_FSM_DONE 0x00000101 /* complete */ + + +/* + * GEM_MII_INTERRUP_STATUS reg + * No mask register; mask with the global interrupt mask register. + */ +#define GEM_MII_INTERRUP_LINK 0x00000004 /* PCS link status change */ /* 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 {G}MII, 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" /* GEM_MII_SLINK_CONTROL reg */ -#define GEM_MII_SLINK_LOOPBACK 0x00000001 /* enable loopback at sl */ +#define GEM_MII_SLINK_LOOPBACK 0x00000001 /* enable loopback at sl, logic + * reversed for 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_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 */ @@ -494,6 +570,13 @@ #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 @@ -524,7 +607,7 @@ struct gem_desc { */ /* Receive flags */ -#define GEM_RD_CHECKSUM 0x000000000000ffffLL +#define GEM_RD_CHECKSUM 0x000000000000ffffLL /* is the complement */ #define GEM_RD_BUFSIZE 0x000000007fff0000LL #define GEM_RD_OWN 0x0000000080000000LL /* 1 - owned by h/w */ #define GEM_RD_HASHVAL 0x0ffff00000000000LL @@ -533,9 +616,6 @@ struct gem_desc { #define GEM_RD_BAD_CRC 0x4000000000000000LL #define GEM_RD_BUFSHIFT 16 -#define GEM_RD_BUFLEN(x) (((x)&GEM_RD_BUFSIZE)>>GEM_RD_BUFSHIFT) - -/* PCI support */ -#define PCI_GEM_BASEADDR 0x10 +#define GEM_RD_BUFLEN(x) (((x) & GEM_RD_BUFSIZE) >> GEM_RD_BUFSHIFT) #endif diff --git a/sys/dev/gem/if_gemvar.h b/sys/dev/gem/if_gemvar.h index 0986a8d..08b2105 100644 --- a/sys/dev/gem/if_gemvar.h +++ b/sys/dev/gem/if_gemvar.h @@ -58,9 +58,8 @@ * Receive descriptor list size. We have one Rx buffer per incoming * packet, so this logic is a little simpler. */ -#define GEM_NRXDESC 128 +#define GEM_NRXDESC 256 #define GEM_NRXDESC_MASK (GEM_NRXDESC - 1) -#define GEM_PREVRX(x) ((x - 1) & GEM_NRXDESC_MASK) #define GEM_NEXTRX(x) ((x + 1) & GEM_NRXDESC_MASK) /* @@ -118,15 +117,15 @@ struct gem_rxsoft { */ struct gem_softc { struct ifnet *sc_ifp; + struct mtx sc_mtx; device_t sc_miibus; struct mii_data *sc_mii; /* MII media control */ device_t sc_dev; /* generic device information */ - u_char sc_enaddr[6]; + u_char sc_enaddr[ETHER_ADDR_LEN]; struct callout sc_tick_ch; /* tick callout */ struct callout sc_rx_ch; /* delayed rx callout */ int sc_wdog_timer; /* watchdog timer */ - /* The following bus handles are to be provided by the bus front-end */ void *sc_ih; struct resource *sc_res[2]; bus_dma_tag_t sc_pdmatag; /* parent bus dma tag */ @@ -135,18 +134,24 @@ struct gem_softc { bus_dma_tag_t sc_cdmatag; /* control data bus dma tag */ bus_dmamap_t sc_dmamap; /* bus dma handle */ - int sc_phys[2]; /* MII instance -> PHY map */ - - int sc_mif_config; /* Selected MII reg setting */ + int sc_phyad; /* addr. of PHY to use or -1 for any */ - 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_GEM 1 /* Sun GEM */ +#define GEM_SUN_ERI 2 /* Sun ERI */ +#define GEM_APPLE_GMAC 3 /* Apple GMAC */ +#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; /* */ -#define GEM_GIGABIT 0x0001 /* has a gigabit PHY */ +#define GEM_INITED (1 << 0) /* reset persistent regs initialized */ +#define GEM_LINK (1 << 1) /* link is up */ +#define GEM_PCI (1 << 2) /* XXX PCI busses are little-endian */ +#define GEM_SERDES (1 << 3) /* use the SERDES */ /* * Ring buffer DMA stuff. @@ -169,33 +174,31 @@ struct gem_softc { #define sc_txdescs sc_control_data->gcd_txdescs #define sc_rxdescs sc_control_data->gcd_rxdescs - int sc_txfree; /* number of free Tx descriptors */ - int sc_txnext; /* next ready Tx descriptor */ - int sc_txwin; /* Tx descriptors since last Tx int */ + int sc_txfree; /* number of free Tx descriptors */ + int sc_txnext; /* next ready Tx descriptor */ + int sc_txwin; /* Tx descriptors since last Tx int */ struct gem_txsq sc_txfreeq; /* free Tx descsofts */ struct gem_txsq sc_txdirtyq; /* dirty Tx descsofts */ - int sc_rxptr; /* next ready RX descriptor/descsoft */ - int sc_rxfifosize; /* Rx FIFO size (bytes) */ + int sc_rxptr; /* next ready RX descriptor/descsoft */ + int sc_rxfifosize; /* Rx FIFO size (bytes) */ /* ========== */ - int sc_inited; - int sc_debug; int sc_ifflags; int sc_csum_features; - - struct mtx sc_mtx; }; -#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) != 0) ? le64toh(v) : be64toh(v)) +#define GEM_DMA_WRITE(sc, v) \ + ((((sc)->sc_flags & GEM_PCI) != 0) ? 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_CDSYNC(sc, ops) \ - bus_dmamap_sync((sc)->sc_cdmatag, (sc)->sc_cddmamap, (ops)); \ + bus_dmamap_sync((sc)->sc_cdmatag, (sc)->sc_cddmamap, (ops)); #define GEM_INIT_RXDESC(sc, x) \ do { \ @@ -208,7 +211,19 @@ do { \ GEM_DMA_WRITE((sc), __rxs->rxs_paddr); \ __rxd->gd_flags = \ GEM_DMA_WRITE((sc), \ - (((__m->m_ext.ext_size)<<GEM_RD_BUFSHIFT) \ + (((__m->m_ext.ext_size) << GEM_RD_BUFSHIFT) \ + & GEM_RD_BUFSIZE) | GEM_RD_OWN); \ +} 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) << GEM_RD_BUFSHIFT) \ & GEM_RD_BUFSIZE) | GEM_RD_OWN); \ } while (0) @@ -231,8 +246,6 @@ void gem_intr(void *); int gem_mediachange(struct ifnet *); void gem_mediastatus(struct ifnet *, struct ifmediareq *); -void gem_reset(struct gem_softc *); - /* MII methods & callbacks */ int gem_mii_readreg(device_t, int, int); int gem_mii_writereg(device_t, int, int, int); @@ -240,5 +253,4 @@ void gem_mii_statchg(device_t); #endif /* _KERNEL */ - #endif diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 79aacc3..4c47167 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -87,7 +87,7 @@ SUBDIR= ${_3dfx} \ firewire \ firmware \ fxp \ - ${_gem} \ + gem \ geom \ ${_harp} \ hatm \ @@ -579,7 +579,6 @@ _ath_hal= ath_hal _ath_rate_amrr= ath_rate_amrr _ath_rate_onoe= ath_rate_onoe _ath_rate_sample=ath_rate_sample -_gem= gem _powermac_nvram= powermac_nvram _smbfs= smbfs .endif @@ -592,7 +591,6 @@ _ath_rate_onoe= ath_rate_onoe _ath_rate_sample=ath_rate_sample _auxio= auxio _em= em -_gem= gem _i2c= i2c _sound= sound .endif diff --git a/sys/powerpc/conf/NOTES b/sys/powerpc/conf/NOTES index 438e2cb..176e661 100644 --- a/sys/powerpc/conf/NOTES +++ b/sys/powerpc/conf/NOTES @@ -20,7 +20,6 @@ options SC_OFWFB # OFW frame buffer # Standard busses device pci -device gem # Sun GEM/Sun ERI/Apple GMAC device ofwd # Open Firmware disks |