summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2007-09-26 21:14:18 +0000
committermarius <marius@FreeBSD.org>2007-09-26 21:14:18 +0000
commit4894db0d57bf9688395e36a6498c1ea0a84238f4 (patch)
tree822b6de41741c67477891d08cef95ef26813fa9d
parent6cdd0265f89f265e1284ffe0eb4f90d219802f8d (diff)
downloadFreeBSD-src-4894db0d57bf9688395e36a6498c1ea0a84238f4.zip
FreeBSD-src-4894db0d57bf9688395e36a6498c1ea0a84238f4.tar.gz
o Revert the part of if_gem.c rev. 1.35 which added a call to gem_stop()
to gem_attach() as the former access softc members not yet initialized at that time and gem_reset() actually is enough to stop the chip. [1] o Revise the use of gem_bitwait(); add bus_barrier() calls before calling gem_bitwait() to ensure the respective bit has been written before we starting polling on it and poll for the right bits to change, f.e. even though we only reset RX we have to actually wait for both GEM_RESET_RX and GEM_RESET_TX to clear. Add some additional gem_bitwait() calls in places we've been missing them according to the GEM documentation. Along with this some excessive DELAYs, which probably only were added because of bugs in gem_bitwait() and its use in the first place, as well as as have of an gem_bitwait() reimplementation in gem_reset_tx() were removed. o Add gem_reset_rxdma() and use it to deal with GEM_MAC_RX_OVERFLOW errors more gracefully as unlike gem_init_locked() it resets the RX DMA engine only, causing no link loss and the FIFOs not to be cleared. Also use it deal with GEM_INTR_RX_TAG_ERR errors, with previously were unhandled. This was based on information obtained from the Linux GEM and OpenSolaris ERI drivers. o Turn on workarounds for silicon bugs in the Apple GMAC variants. This was based on information obtained from the Darwin GMAC and Linux GEM drivers. o Turn on "infinite" (i.e. maximum 31 * 64 bytes in length) DMA bursts. This greatly improves especially RX performance. o Optimize the RX path, this consists of: - kicking the receiver as soon as we've a spare descriptor in gem_rint() again instead of just once after all the ready ones have been handled; - kicking the receiver the right way, i.e. as outlined in the GEM documentation in batches of 4 and by pointing it to the descriptor after the last valid one; - calling gem_rint() before gem_tint() in gem_intr() as gem_tint() may take quite a while; - doubling the size of the RX ring to 256 descriptors. Overall the RX performance of a GEM in a 1GHz Sun Fire V210 was improved from ~100Mbit/s to ~850Mbit/s. o In gem_add_rxbuf() don't assign the newly allocated mbuf to rxs_mbuf before calling bus_dmamap_load_mbuf_sg(), if bus_dmamap_load_mbuf_sg() fails we'll free the newly allocated mbuf, unable to recycle the previous one but a NULL pointer dereference instead. o In gem_init_locked() honor the return value of gem_meminit(). o Simplify gem_ringsize() and dont' return garbage in the default case. Based on OpenBSD. o Don't turn on MAC control, MIF and PCS interrupts unless GEM_DEBUG is defined as we don't need/use these interrupts for operation. o In gem_start_locked() sync the DMA maps of the descriptor rings before every kick of the transmitter and not just once after enqueuing all packets as the NIC might instantly start transmitting after we kicked it the first time. o Keep state of the link state and use it to enable or disable the MAC in gem_mii_statchg() accordingly as well as to return early from gem_start_locked() in case the link is down. [3] o Initialize the maximum frame size to a sane value. o In gem_mii_statchg() enable carrier extension if appropriate. o Increment if_ierrors in case of an GEM_MAC_RX_OVERFLOW error and in gem_eint(). [3] o Handle IFF_ALLMULTI correctly; don't set it if we've turned promiscuous group mode on and don't clear the flag if we've disabled promiscuous group mode (these were mostly NOPs though). [2] o Let gem_eint() also report GEM_INTR_PERR errors. o Move setting sc_variant from gem_pci_probe() to gem_pci_attach() as device probe methods are not supposed to touch the softc. o Collapse sc_inited and sc_pci into bits for sc_flags. o Add CTASSERTs ensuring that GEM_NRXDESC and GEM_NTXDESC are set to legal values. o Correctly set up for 802.3x flow control, though #ifdef out the code that actually enables it as this needs more testing and mainly a proper framework to support it. o Correct and add some conversions from hard-coded functions names to __func__ which were borked or forgotten in if_gem.c rev. 1.42. o Use PCIR_BAR instead of a homegrown macro. o Replace sc_enaddr[6] with sc_enaddr[ETHER_ADDR_LEN]. o In gem_pci_attach() in case attaching fails release the resources in the opposite order they were allocated. o Make gem_reset() static to if_gem.c as it's not needed outside that module. o Remove the GEM_GIGABIT flag and the associated code; GEM_GIGABIT was never set and the associated code was in the wrong place. o Remove sc_mif_config; it was only used to cache the contents of the respective register within gem_attach(). o Remove the #ifdef'ed out NetBSD/OpenBSD code for establishing a suspend hook as it will never be used on FreeBSD. o Also probe Apple Intrepid 2 GMAC and Apple Shasta GMAC, add support for Apple K2 GMAC. Based on OpenBSD. o Add support for Sun GBE/P cards, or in other words actually add support for cards based on GEM to gem(4). This mainly consists of adding support for the TBI of these chips. Along with this the PHY selection code was rewritten to hardcode the PHY number for certain configurations as for example the PHY of the on-board ERI of Blade 1000 shows up twice causing no link as the second incarnation is isolated. These changes were ported from OpenBSD with some additional improvements and modulo some bugs. o Add code to if_gem_pci.c allowing to read the MAC-address from the VPD on systems without Open Firmware. This is an improved version of my variant of the respective code in if_hme_pci.c o Now that gem(4) is MI enable it for all archs. Pointed out by: yongari [1] Suggested by: rwatson [2], yongari [3] Tested on: i386 (GEM), powerpc (GMACs by marcel and yongari), sparc64 (ERI and GEM) Reviewed by: yongari Approved by: re (kensmith)
-rw-r--r--share/man/man4/gem.419
-rw-r--r--sys/conf/NOTES2
-rw-r--r--sys/dev/gem/if_gem.c812
-rw-r--r--sys/dev/gem/if_gem_pci.c165
-rw-r--r--sys/dev/gem/if_gemreg.h148
-rw-r--r--sys/dev/gem/if_gemvar.h66
-rw-r--r--sys/modules/Makefile4
-rw-r--r--sys/powerpc/conf/NOTES1
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
OpenPOWER on IntegriCloud