summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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