Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Jun 2009 20:36:59 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r194763 - in head/sys: conf dev/gem modules/gem
Message-ID:  <200906232036.n5NKax9O089354@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marius
Date: Tue Jun 23 20:36:59 2009
New Revision: 194763
URL: http://svn.freebsd.org/changeset/base/194763

Log:
  - Initialize the ifnet structure, especially if_dname, before probing
    the PHYs as some PHY drivers use it (but probably shouldn't). How
    gem(4) has worked with brgphy(4) on powerpc without this so far is
    unclear to me.
  - Introduce a dying flag which is set during detach and checked in
    gem_ioctl() in order to prevent active BPF listeners to clear
    promiscuous mode which may lead to the tick callout being restarted
    which will trigger a panic once it's actually gone.
  - In gem_stop() reset rather than just disable the transmitter and
    receiver in order to ensure we're not unloading DMA maps still in
    use by the hardware. [1]
  - The blanking time is specified in PCI clocks so we should use twice
    the value when operating at 66MHz.
  - Spell some 2 as ETHER_ALIGN and a 19 as GEM_STATUS_TX_COMPLETION_SHFT
    to make the actual intentions clear.
  - As we don't unload the peak attempts counter ignore its overflow
    interrupts.
  - Remove a stale setting of a variable to GEM_TD_INTERRUPT_ME which
    isn't used afterwards.
  - For optimum performance increment the TX kick register in multiples
    of 4 if possible as suggested by the documentation.
  - Partially revert r164931; drivers should only clear the watchdog
    timer if all outstanding TX descriptors are done.
  - Fix some debugging strings.
  - Add a missing BUS_DMASYNC_POSTWRITE in gem_rint().
  - As the error paths in the interrupt handler are generally unlikely
    predict them as false.
  - Add support for the SBus version of the GEM controller. [2]
  - Add some lock assertions.
  - Improve some comments.
  - Fix some more or less cosmetic issues in the code of the PCI front-end.
  - Change some softc members to be unsigned where more appropriate and
    remove unused ones.
  
  Approved by:	re (kib)
  Obtained from:	NetBSD (partially) [2], OpenBSD [1]
  MFC after:	2 weeks

Added:
  head/sys/dev/gem/if_gem_sbus.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/gem/if_gem.c
  head/sys/dev/gem/if_gem_pci.c
  head/sys/dev/gem/if_gemreg.h
  head/sys/dev/gem/if_gemvar.h
  head/sys/modules/gem/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Jun 23 20:35:51 2009	(r194762)
+++ head/sys/conf/files	Tue Jun 23 20:36:59 2009	(r194763)
@@ -923,6 +923,7 @@ dev/flash/at45d.c		optional at45d
 dev/fxp/if_fxp.c		optional fxp inet
 dev/gem/if_gem.c		optional gem
 dev/gem/if_gem_pci.c		optional gem pci
+dev/gem/if_gem_sbus.c		optional gem sbus
 dev/hatm/if_hatm.c		optional hatm pci
 dev/hatm/if_hatm_intr.c		optional hatm pci
 dev/hatm/if_hatm_ioctl.c	optional hatm pci

Modified: head/sys/dev/gem/if_gem.c
==============================================================================
--- head/sys/dev/gem/if_gem.c	Tue Jun 23 20:35:51 2009	(r194762)
+++ head/sys/dev/gem/if_gem.c	Tue Jun 23 20:36:59 2009	(r194763)
@@ -84,7 +84,7 @@ __FBSDID("$FreeBSD$");
 CTASSERT(powerof2(GEM_NRXDESC) && GEM_NRXDESC >= 32 && GEM_NRXDESC <= 8192);
 CTASSERT(powerof2(GEM_NTXDESC) && GEM_NTXDESC >= 32 && GEM_NTXDESC <= 8192);
 
-#define	TRIES	10000
+#define	GEM_TRIES	10000
 
 /*
  * The hardware supports basic TCP/UDP checksum offloading.  However,
@@ -119,7 +119,7 @@ static void	gem_rint(struct gem_softc *s
 #ifdef GEM_RINT_TIMEOUT
 static void	gem_rint_timeout(void *arg);
 #endif
-static __inline void gem_rxcksum(struct mbuf *m, uint64_t flags);
+static inline void gem_rxcksum(struct mbuf *m, uint64_t flags);
 static void	gem_rxdrain(struct gem_softc *sc);
 static void	gem_setladrf(struct gem_softc *sc);
 static void	gem_start(struct ifnet *ifp);
@@ -127,6 +127,7 @@ static void	gem_start_locked(struct ifne
 static void	gem_stop(struct ifnet *ifp, int disable);
 static void	gem_tick(void *arg);
 static void	gem_tint(struct gem_softc *sc);
+static inline void gem_txkick(struct gem_softc *sc);
 static int	gem_watchdog(struct gem_softc *sc);
 
 devclass_t gem_devclass;
@@ -151,9 +152,24 @@ gem_attach(struct gem_softc *sc)
 	int error, i;
 	uint32_t v;
 
+	if (bootverbose)
+		device_printf(sc->sc_dev, "flags=0x%x\n", sc->sc_flags);
+
+	/* Set up ifnet structure. */
 	ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL)
 		return (ENOSPC);
+	sc->sc_csum_features = GEM_CSUM_FEATURES;
+	ifp->if_softc = sc;
+	if_initname(ifp, device_get_name(sc->sc_dev),
+	    device_get_unit(sc->sc_dev));
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_start = gem_start;
+	ifp->if_ioctl = gem_ioctl;
+	ifp->if_init = gem_init;
+	IFQ_SET_MAXLEN(&ifp->if_snd, GEM_TXQUEUELEN);
+	ifp->if_snd.ifq_drv_maxlen = GEM_TXQUEUELEN;
+	IFQ_SET_READY(&ifp->if_snd);
 
 	callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0);
 #ifdef GEM_RINT_TIMEOUT
@@ -161,27 +177,26 @@ gem_attach(struct gem_softc *sc)
 #endif
 
 	/* Make sure the chip is stopped. */
-	ifp->if_softc = sc;
 	gem_reset(sc);
 
 	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
 	    BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,
 	    NULL, &sc->sc_pdmatag);
-	if (error)
+	if (error != 0)
 		goto fail_ifnet;
 
 	error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0,
 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
 	    1, MCLBYTES, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_rdmatag);
-	if (error)
+	if (error != 0)
 		goto fail_ptag;
 
 	error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0,
 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    MCLBYTES * GEM_NTXSEGS, GEM_NTXSEGS, MCLBYTES,
 	    BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_tdmatag);
-	if (error)
+	if (error != 0)
 		goto fail_rtag;
 
 	error = bus_dma_tag_create(sc->sc_pdmatag, PAGE_SIZE, 0,
@@ -189,7 +204,7 @@ gem_attach(struct gem_softc *sc)
 	    sizeof(struct gem_control_data), 1,
 	    sizeof(struct gem_control_data), 0,
 	    NULL, NULL, &sc->sc_cdmatag);
-	if (error)
+	if (error != 0)
 		goto fail_ttag;
 
 	/*
@@ -199,7 +214,7 @@ gem_attach(struct gem_softc *sc)
 	if ((error = bus_dmamem_alloc(sc->sc_cdmatag,
 	    (void **)&sc->sc_control_data,
 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
-	    &sc->sc_cddmamap))) {
+	    &sc->sc_cddmamap)) != 0) {
 		device_printf(sc->sc_dev,
 		    "unable to allocate control data, error = %d\n", error);
 		goto fail_ctag;
@@ -338,19 +353,6 @@ gem_attach(struct gem_softc *sc)
 	device_printf(sc->sc_dev, "%ukB RX FIFO, %ukB TX FIFO\n",
 	    sc->sc_rxfifosize / 1024, v / 16);
 
-	sc->sc_csum_features = GEM_CSUM_FEATURES;
-	/* Initialize ifnet structure. */
-	ifp->if_softc = sc;
-	if_initname(ifp, device_get_name(sc->sc_dev),
-	    device_get_unit(sc->sc_dev));
-	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_start = gem_start;
-	ifp->if_ioctl = gem_ioctl;
-	ifp->if_init = gem_init;
-	IFQ_SET_MAXLEN(&ifp->if_snd, GEM_TXQUEUELEN);
-	ifp->if_snd.ifq_drv_maxlen = GEM_TXQUEUELEN;
-	IFQ_SET_READY(&ifp->if_snd);
-
 	/* Attach the interface. */
 	ether_ifattach(ifp, sc->sc_enaddr);
 
@@ -402,6 +404,7 @@ gem_detach(struct gem_softc *sc)
 	int i;
 
 	GEM_LOCK(sc);
+	sc->sc_flags |= GEM_DYING;
 	gem_stop(ifp, 1);
 	GEM_UNLOCK(sc);
 	callout_drain(&sc->sc_tick_ch);
@@ -456,7 +459,7 @@ gem_resume(struct gem_softc *sc)
 	GEM_UNLOCK(sc);
 }
 
-static __inline void
+static inline void
 gem_rxcksum(struct mbuf *m, uint64_t flags)
 {
 	struct ether_header *eh;
@@ -535,12 +538,11 @@ static void
 gem_tick(void *arg)
 {
 	struct gem_softc *sc = arg;
-	struct ifnet *ifp;
+	struct ifnet *ifp = sc->sc_ifp;
 	uint32_t v;
 
 	GEM_LOCK_ASSERT(sc, MA_OWNED);
 
-	ifp = sc->sc_ifp;
 	/*
 	 * Unload collision and error counters.
 	 */
@@ -584,7 +586,7 @@ gem_bitwait(struct gem_softc *sc, u_int 
 	int i;
 	uint32_t reg;
 
-	for (i = TRIES; i--; DELAY(100)) {
+	for (i = GEM_TRIES; i--; DELAY(100)) {
 		reg = GEM_BANKN_READ_M(bank, 4, sc, r);
 		if ((reg & clr) == 0 && (reg & set) == set)
 			return (1);
@@ -593,8 +595,7 @@ gem_bitwait(struct gem_softc *sc, u_int 
 }
 
 static void
-gem_reset(sc)
-	struct gem_softc *sc;
+gem_reset(struct gem_softc *sc)
 {
 
 #ifdef GEM_DEBUG
@@ -644,9 +645,8 @@ gem_stop(struct ifnet *ifp, int disable)
 	callout_stop(&sc->sc_rx_ch);
 #endif
 
-	/* XXX should we reset these instead? */
-	gem_disable_tx(sc);
-	gem_disable_rx(sc);
+	gem_reset_tx(sc);
+	gem_reset_rx(sc);
 
 	/*
 	 * Release any queued transmit buffers.
@@ -721,7 +721,7 @@ gem_reset_rxdma(struct gem_softc *sc)
 		if (sc->sc_rxsoft[i].rxs_mbuf != NULL)
 			GEM_UPDATE_RXDESC(sc, i);
 	sc->sc_rxptr = 0;
-	GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+	GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 	/* NOTE: we use only 32-bit DMA addresses here. */
 	GEM_BANK1_WRITE_4(sc, GEM_RX_RING_PTR_HI, 0);
@@ -732,9 +732,11 @@ gem_reset_rxdma(struct gem_softc *sc)
 	    ((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));
+	    (ETHER_ALIGN << GEM_RX_CONFIG_FBOFF_SHFT));
+	/* Adjust for the SBus clock probably isn't worth the fuzz. */
 	GEM_BANK1_WRITE_4(sc, GEM_RX_BLANKING,
-	    (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6);
+	    ((6 * (sc->sc_flags & GEM_PCI66) != 0 ? 2 : 1) <<
+	    GEM_RX_BLANKING_TIME_SHIFT) | 6);
 	GEM_BANK1_WRITE_4(sc, GEM_RX_PAUSE_THRESH,
 	    (3 * sc->sc_rxfifosize / 256) |
 	    ((sc->sc_rxfifosize / 256) << 12));
@@ -798,12 +800,13 @@ gem_disable_tx(struct gem_softc *sc)
 }
 
 static int
-gem_meminit(sc)
-	struct gem_softc *sc;
+gem_meminit(struct gem_softc *sc)
 {
 	struct gem_rxsoft *rxs;
 	int error, i;
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	/*
 	 * Initialize the transmit descriptor ring.
 	 */
@@ -837,7 +840,8 @@ gem_meminit(sc)
 			GEM_INIT_RXDESC(sc, i);
 	}
 	sc->sc_rxptr = 0;
-	GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+	GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 	return (0);
 }
@@ -938,6 +942,20 @@ gem_init_locked(struct gem_softc *sc)
 #endif
 
 	/* step 8.  Global Configuration & Interrupt Mask */
+
+	/*
+	 * 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
+	 * RX performance.
+	 * Enable silicon bug workarounds for the Apple variants.
+	 */
+	GEM_BANK1_WRITE_4(sc, GEM_CONFIG,
+	    GEM_CONFIG_TXDMA_LIMIT | GEM_CONFIG_RXDMA_LIMIT |
+	    ((sc->sc_flags & GEM_PCI) != 0 ? GEM_CONFIG_BURST_INF :
+	    GEM_CONFIG_BURST_64) | (GEM_IS_APPLE(sc) ?
+	    GEM_CONFIG_RONPAULBIT | GEM_CONFIG_BUG2FIX : 0));
+
 	GEM_BANK1_WRITE_4(sc, 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_PERR |
@@ -949,7 +967,8 @@ gem_init_locked(struct gem_softc *sc)
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_MASK,
 	    GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT);
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_MASK,
-	    GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP);
+	    GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP |
+	    GEM_MAC_TX_PEAK_EXP);
 #ifdef GEM_DEBUG
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_MASK,
 	    ~(GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME));
@@ -961,7 +980,8 @@ gem_init_locked(struct gem_softc *sc)
 	/* step 9.  ETX Configuration: use mostly default values. */
 
 	/* Enable DMA. */
-	v = gem_ringsize(GEM_NTXDESC /* XXX */);
+	v = gem_ringsize(GEM_NTXDESC);
+	/* Set TX FIFO threshold and enable DMA. */
 	v |= ((sc->sc_variant == GEM_SUN_ERI ? 0x100 : 0x4ff) << 10) &
 	    GEM_TX_CONFIG_TXFIFO_TH;
 	GEM_BANK1_WRITE_4(sc, GEM_TX_CONFIG, v | GEM_TX_CONFIG_TXDMA_EN);
@@ -973,14 +993,16 @@ gem_init_locked(struct gem_softc *sc)
 	/* RX TCP/UDP checksum offset */
 	v |= ((ETHER_HDR_LEN + sizeof(struct ip)) <<
 	    GEM_RX_CONFIG_CXM_START_SHFT);
-
-	/* Enable DMA. */
+	/* Set RX FIFO threshold, set first byte offset and enable DMA. */
 	GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG,
 	    v | (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) |
-	    (2 << GEM_RX_CONFIG_FBOFF_SHFT) | GEM_RX_CONFIG_RXDMA_EN);
+	    (ETHER_ALIGN << GEM_RX_CONFIG_FBOFF_SHFT) |
+	    GEM_RX_CONFIG_RXDMA_EN);
 
+	/* Adjust for the SBus clock probably isn't worth the fuzz. */
 	GEM_BANK1_WRITE_4(sc, GEM_RX_BLANKING,
-	    (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6);
+	    ((6 * (sc->sc_flags & GEM_PCI66) != 0 ? 2 : 1) <<
+	    GEM_RX_BLANKING_TIME_SHIFT) | 6);
 
 	/*
 	 * The following value is for an OFF Threshold of about 3/4 full
@@ -1002,7 +1024,7 @@ gem_init_locked(struct gem_softc *sc)
 		device_printf(sc->sc_dev, "cannot configure RX MAC\n");
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v);
 
-	/* step 13. TX_MAC Configuration Register */
+	/* step 13.  TX_MAC Configuration Register */
 	v = GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG);
 	v |= GEM_MAC_TX_ENABLE;
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 0);
@@ -1037,6 +1059,8 @@ gem_load_txmbuf(struct gem_softc *sc, st
 	uint64_t cflags, flags;
 	int error, nexttx, nsegs, offset, seg;
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	/* Get a work queue entry. */
 	if ((txs = STAILQ_FIRST(&sc->sc_txfreeq)) == NULL) {
 		/* Ran out of descriptors. */
@@ -1143,7 +1167,6 @@ gem_load_txmbuf(struct gem_softc *sc, st
 #endif
 	if (++sc->sc_txwin > GEM_NTXSEGS * 2 / 3) {
 		sc->sc_txwin = 0;
-		flags |= GEM_TD_INTERRUPT_ME;
 		sc->sc_txdescs[txs->txs_firstdesc].gd_flags |=
 		    GEM_DMA_WRITE(sc, GEM_TD_INTERRUPT_ME |
 		    GEM_TD_START_OF_PACKET);
@@ -1175,6 +1198,8 @@ gem_init_regs(struct gem_softc *sc)
 {
 	const u_char *laddr = IF_LLADDR(sc->sc_ifp);
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	/* These registers are not cleared on reset. */
 	if ((sc->sc_flags & GEM_INITED) == 0) {
 		/* magic values */
@@ -1182,16 +1207,19 @@ gem_init_regs(struct gem_softc *sc)
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_IPG1, 8);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_IPG2, 4);
 
+		/* min frame length */
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN);
-		/* max frame and max burst size */
+		/* max frame length and max burst size */
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_MAC_MAX_FRAME,
 		    (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) | (0x2000 << 16));
 
+		/* more magic values */
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_PREAMBLE_LEN, 0x7);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_JAM_SIZE, 0x4);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ATTEMPT_LIMIT, 0x10);
-		/* dunno... */
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_TYPE, 0x8088);
+
+		/* random number seed */
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_RANDOM_SEED,
 		    ((laddr[5] << 8) | laddr[4]) & 0x3ff);
 
@@ -1209,7 +1237,6 @@ gem_init_regs(struct gem_softc *sc)
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER0, 0);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER1, 0);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER2, 0);
-
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ADR_FLT_MASK1_2, 0);
 		GEM_BANK1_WRITE_4(sc, GEM_MAC_ADR_FLT_MASK0, 0);
 
@@ -1232,18 +1259,6 @@ gem_init_regs(struct gem_softc *sc)
 	/* Set XOFF PAUSE time. */
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_SEND_PAUSE_CMD, 0x1BF0);
 
-	/*
-	 * 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.
-	 */
-	GEM_BANK1_WRITE_4(sc, 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. */
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR0, (laddr[4] << 8) | laddr[5]);
 	GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR1, (laddr[2] << 8) | laddr[3]);
@@ -1263,12 +1278,32 @@ gem_start(struct ifnet *ifp)
 	GEM_UNLOCK(sc);
 }
 
+static inline void
+gem_txkick(struct gem_softc *sc)
+{
+
+	/*
+	 * Update the TX kick register.  This register has to point to the
+	 * descriptor after the last valid one and for optimum performance
+	 * should be incremented in multiples of 4 (the DMA engine fetches/
+	 * updates descriptors in batches of 4).
+	 */
+#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_PREREAD | BUS_DMASYNC_PREWRITE);
+	GEM_BANK1_WRITE_4(sc, GEM_TX_KICK, sc->sc_txnext);
+}
+
 static void
 gem_start_locked(struct ifnet *ifp)
 {
 	struct gem_softc *sc = ifp->if_softc;
 	struct mbuf *m;
-	int ntx;
+	int kicked, ntx;
+
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
 
 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
 	    IFF_DRV_RUNNING || (sc->sc_flags & GEM_LINK) == 0)
@@ -1280,6 +1315,7 @@ gem_start_locked(struct ifnet *ifp)
 	    sc->sc_txnext);
 #endif
 	ntx = 0;
+	kicked = 0;
 	for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->sc_txfree > 1;) {
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL)
@@ -1291,19 +1327,18 @@ gem_start_locked(struct ifnet *ifp)
 			IFQ_DRV_PREPEND(&ifp->if_snd, m);
 			break;
 		}
+		if ((sc->sc_txnext % 4) == 0) {
+			gem_txkick(sc);
+			kicked = 1;
+		} else
+			kicked = 0;
 		ntx++;
-		/* Kick the transmitter. */
-#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_PREREAD | BUS_DMASYNC_PREWRITE);
-		GEM_BANK1_WRITE_4(sc, GEM_TX_KICK, sc->sc_txnext);
-
 		BPF_MTAP(ifp, m);
 	}
 
 	if (ntx > 0) {
+		if (kicked == 0)
+			gem_txkick(sc);
 #ifdef GEM_DEBUG
 		CTR2(KTR_GEM, "%s: packets enqueued, OWN on %d",
 		    device_get_name(sc->sc_dev), sc->sc_txnext);
@@ -1324,10 +1359,13 @@ gem_tint(struct gem_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
 	struct gem_txsoft *txs;
-	int txlast, progress;
+	int progress;
+	uint32_t txlast;
 #ifdef GEM_DEBUG
 	int i;
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__);
 #endif
 
@@ -1338,7 +1376,6 @@ gem_tint(struct gem_softc *sc)
 	progress = 0;
 	GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD);
 	while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
-
 #ifdef GEM_DEBUG
 		if ((ifp->if_flags & IFF_DEBUG) != 0) {
 			printf("    txsoft %p transmit chain:\n", txs);
@@ -1419,8 +1456,8 @@ gem_tint(struct gem_softc *sc)
 		 * and restart.
 		 */
 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-		sc->sc_wdog_timer = STAILQ_EMPTY(&sc->sc_txdirtyq) ? 0 : 5;
-
+		if (STAILQ_EMPTY(&sc->sc_txdirtyq))
+		    sc->sc_wdog_timer = 0;
 		gem_start_locked(ifp);
 	}
 
@@ -1437,6 +1474,7 @@ gem_rint_timeout(void *arg)
 	struct gem_softc *sc = arg;
 
 	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	gem_rint(sc);
 }
 #endif
@@ -1449,6 +1487,8 @@ gem_rint(struct gem_softc *sc)
 	uint64_t rxstat;
 	uint32_t rxcomp;
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 #ifdef GEM_RINT_TIMEOUT
 	callout_stop(&sc->sc_rx_ch);
 #endif
@@ -1461,12 +1501,11 @@ gem_rint(struct gem_softc *sc)
 	 * how long the following loop can execute.
 	 */
 	rxcomp = GEM_BANK1_READ_4(sc, GEM_RX_COMPLETION);
-
 #ifdef GEM_DEBUG
-	CTR3(KTR_GEM, "%s: sc->rxptr %d, complete %d",
+	CTR3(KTR_GEM, "%s: sc->sc_rxptr %d, complete %d",
 	    __func__, sc->sc_rxptr, rxcomp);
 #endif
-	GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD);
+	GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 	for (; sc->sc_rxptr != rxcomp;) {
 		m = sc->sc_rxsoft[sc->sc_rxptr].rxs_mbuf;
 		rxstat = GEM_DMA_READ(sc,
@@ -1525,9 +1564,9 @@ gem_rint(struct gem_softc *sc)
 		/*
 		 * 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).
+		 * current batch) and for optimum performance should be
+		 * incremented in multiples of 4 (the DMA engine fetches/
+		 * updates descriptors in batches of 4).
 		 */
 		sc->sc_rxptr = GEM_NEXTRX(sc->sc_rxptr);
 		if ((sc->sc_rxptr % 4) == 0) {
@@ -1545,7 +1584,7 @@ gem_rint(struct gem_softc *sc)
 		}
 
 		ifp->if_ipackets++;
-		m->m_data += 2; /* We're already off by two */
+		m->m_data += ETHER_ALIGN; /* first byte offset */
 		m->m_pkthdr.rcvif = ifp;
 		m->m_pkthdr.len = m->m_len = GEM_RD_BUFLEN(rxstat);
 
@@ -1559,7 +1598,7 @@ gem_rint(struct gem_softc *sc)
 	}
 
 #ifdef GEM_DEBUG
-	CTR3(KTR_GEM, "%s: done sc->rxptr %d, complete %d", __func__,
+	CTR3(KTR_GEM, "%s: done sc->sc_rxptr %d, complete %d", __func__,
 	    sc->sc_rxptr, GEM_BANK1_READ_4(sc, GEM_RX_COMPLETION));
 #endif
 }
@@ -1572,6 +1611,8 @@ gem_add_rxbuf(struct gem_softc *sc, int 
 	bus_dma_segment_t segs[1];
 	int error, nsegs;
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
 	if (m == NULL)
 		return (ENOBUFS);
@@ -1620,7 +1661,15 @@ gem_eint(struct gem_softc *sc, u_int sta
 		return;
 	}
 
-	device_printf(sc->sc_dev, "%s: status=%x\n", __func__, status);
+	device_printf(sc->sc_dev, "%s: status 0x%x", __func__, status);
+	if ((status & GEM_INTR_BERR) != 0) {
+		if ((sc->sc_flags & GEM_PCI) != 0)
+			printf(", PCI bus error 0x%x\n",
+			    GEM_BANK1_READ_4(sc, GEM_PCI_ERROR_STATUS));
+		else
+			printf(", SBus error 0x%x\n",
+			    GEM_BANK1_READ_4(sc, GEM_SBUS_STATUS));
+	}
 }
 
 void
@@ -1634,8 +1683,8 @@ gem_intr(void *v)
 
 #ifdef GEM_DEBUG
 	CTR4(KTR_GEM, "%s: %s: cplt %x, status %x",
-	    device_get_name(sc->sc_dev), __func__, (status >> 19),
-	    (u_int)status);
+	    device_get_name(sc->sc_dev), __func__,
+	    (status >> GEM_STATUS_TX_COMPLETION_SHFT), (u_int)status);
 
 	/*
 	 * PCS interrupts must be cleared, otherwise no traffic is passed!
@@ -1665,7 +1714,7 @@ gem_intr(void *v)
 		device_printf(sc->sc_dev, "%s: MIF interrupt\n", __func__);
 #endif
 
-	if ((status &
+	if (__predict_false(status &
 	    (GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR | GEM_INTR_BERR)) != 0)
 		gem_eint(sc, status);
 
@@ -1675,17 +1724,20 @@ gem_intr(void *v)
 	if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0)
 		gem_tint(sc);
 
-	if (status & GEM_INTR_TX_MAC) {
+	if (__predict_false((status & GEM_INTR_TX_MAC) != 0)) {
 		status2 = GEM_BANK1_READ_4(sc, GEM_MAC_TX_STATUS);
 		if ((status2 &
-		    ~(GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP)) != 0)
+		    ~(GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP |
+		    GEM_MAC_TX_PEAK_EXP)) != 0)
 			device_printf(sc->sc_dev,
 			    "MAC TX fault, status %x\n", status2);
 		if ((status2 &
-		    (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG)) != 0)
+		    (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG)) != 0) {
+			sc->sc_ifp->if_oerrors++;
 			gem_init_locked(sc);
+		}
 	}
-	if (status & GEM_INTR_RX_MAC) {
+	if (__predict_false((status & GEM_INTR_RX_MAC) != 0)) {
 		status2 = GEM_BANK1_READ_4(sc, GEM_MAC_RX_STATUS);
 		/*
 		 * At least with GEM_SUN_GEM and some GEM_SUN_ERI
@@ -1906,6 +1958,8 @@ gem_mii_statchg(device_t dev)
 
 	sc = device_get_softc(dev);
 
+	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 #ifdef GEM_DEBUG
 	if ((sc->sc_ifp->if_flags & IFF_DEBUG) != 0)
 		device_printf(sc->sc_dev, "%s: status change: PHY = %d\n",
@@ -1985,7 +2039,7 @@ gem_mii_statchg(device_t dev)
 		if ((GEM_BANK1_READ_4(sc, GEM_MIF_CONFIG) &
 		    GEM_MIF_CONFIG_PHY_SEL) != 0) {
 			/* External MII needs echo disable if half duplex. */
-		    	if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
+			if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
 			    IFM_FDX) == 0)
 				v |= GEM_MAC_XIF_ECHO_DISABL;
 		} else
@@ -2053,6 +2107,11 @@ gem_ioctl(struct ifnet *ifp, u_long cmd,
 	switch (cmd) {
 	case SIOCSIFFLAGS:
 		GEM_LOCK(sc);
+		if ((sc->sc_flags & GEM_DYING) != 0) {
+			error = EINVAL;
+			GEM_UNLOCK(sc);
+			break;
+		}
 		if ((ifp->if_flags & IFF_UP) != 0) {
 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
 			    ((ifp->if_flags ^ sc->sc_ifflags) &

Modified: head/sys/dev/gem/if_gem_pci.c
==============================================================================
--- head/sys/dev/gem/if_gem_pci.c	Tue Jun 23 20:35:51 2009	(r194762)
+++ head/sys/dev/gem/if_gem_pci.c	Tue Jun 23 20:36:59 2009	(r194763)
@@ -90,7 +90,7 @@ static device_method_t gem_pci_methods[]
 	DEVMETHOD(miibus_writereg,	gem_mii_writereg),
 	DEVMETHOD(miibus_statchg,	gem_mii_statchg),
 
-	{ 0, 0 }
+	KOBJMETHOD_END
 };
 
 static driver_t gem_pci_driver = {
@@ -107,7 +107,7 @@ static const struct gem_pci_dev {
 	uint32_t	gpd_devid;
 	int		gpd_variant;
 	const char	*gpd_desc;
-} gem_pci_devlist[] = {
+} const gem_pci_devlist[] = {
 	{ 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" },
@@ -200,13 +200,18 @@ gem_pci_attach(device_t dev)
 	    GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE,
 	    &sc->sc_res[GEM_RES_BANK2]->r_bushandle);
 
+	/* Determine whether we're running at 66MHz. */
+	if ((GEM_BANK2_READ_4(sc, GEM_PCI_BIF_CONFIG) &
+	   GEM_PCI_BIF_CNF_M66EN) != 0)
+		sc->sc_flags |= GEM_PCI66;
+
 #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.
+	 * The VPD 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.
 	 */
@@ -225,22 +230,21 @@ gem_pci_attach(device_t dev)
 #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_VPDRES_LARGE_SIZE		0x03
+#define	PCI_VPDRES_TYPE_VPD		0x10		/* large */
 #define	PCI_VPD_KEY0			0x00
 #define	PCI_VPD_KEY1			0x01
 #define	PCI_VPD_LEN			0x02
-#define	PCI_VPD_DATA			0x03
+#define	PCI_VPD_SIZE			0x03
 
 #define	GEM_ROM_READ_1(sc, offs)					\
-    GEM_BANK1_READ_1((sc), GEM_PCI_ROM_OFFSET + (offs))
+	GEM_BANK1_READ_1((sc), GEM_PCI_ROM_OFFSET + (offs))
 #define	GEM_ROM_READ_2(sc, offs)					\
-    GEM_BANK1_READ_2((sc), GEM_PCI_ROM_OFFSET + (offs))
+	GEM_BANK1_READ_2((sc), GEM_PCI_ROM_OFFSET + (offs))
 #define	GEM_ROM_READ_4(sc, offs)					\
-    GEM_BANK1_READ_4((sc), GEM_PCI_ROM_OFFSET + (offs))
+	GEM_BANK1_READ_4((sc), GEM_PCI_ROM_OFFSET + (offs))
 
 	/* Read PCI Expansion ROM header. */
 	if (GEM_ROM_READ_2(sc, PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC ||
@@ -273,22 +277,22 @@ gem_pci_attach(device_t dev)
 	    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_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) !=
+	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_SIZE + PCI_VPD_KEY0) !=
 	    0x4e /* N */ ||
-	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) !=
+	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_SIZE + PCI_VPD_KEY1) !=
 	    0x41 /* A */ ||
-	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) !=
+	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_SIZE + PCI_VPD_LEN) !=
 	    ETHER_ADDR_LEN ||
-	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA +
+	    GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_SIZE + PCI_VPD_SIZE +
 	    ETHER_ADDR_LEN) != 0x79) {
 		device_printf(dev, "unexpected PCI VPD\n");
 		goto fail;
 	}
 	bus_read_region_1(sc->sc_res[GEM_RES_BANK1],
-	    GEM_PCI_ROM_OFFSET + j + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA,
+	    GEM_PCI_ROM_OFFSET + j + PCI_VPDRES_LARGE_SIZE + PCI_VPD_SIZE,
 	    sc->sc_enaddr, ETHER_ADDR_LEN);
 #endif
 
@@ -330,19 +334,15 @@ gem_pci_detach(device_t dev)
 static int
 gem_pci_suspend(device_t dev)
 {
-	struct gem_softc *sc;
 
-	sc = device_get_softc(dev);
-	gem_suspend(sc);
+	gem_suspend(device_get_softc(dev));
 	return (0);
 }
 
 static int
 gem_pci_resume(device_t dev)
 {
-	struct gem_softc *sc;
 
-	sc = device_get_softc(dev);
-	gem_resume(sc);
+	gem_resume(device_get_softc(dev));
 	return (0);
 }

Added: head/sys/dev/gem/if_gem_sbus.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gem/if_gem_sbus.c	Tue Jun 23 20:36:59 2009	(r194763)
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (C) 2001 Eduardo Horvath.
+ * Copyright (c) 2007 Marius Strobl <marius@FreeBSD.org>
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * 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$");
+
+/*
+ * SBus bindings for Sun GEM Ethernet controllers
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.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 <net/ethernet.h>
+#include <net/if.h>
+
+#include <dev/ofw/ofw_bus.h>
+
+#include <machine/bus.h>
+#include <machine/ofw_machdep.h>
+#include <machine/resource.h>
+
+#include <sparc64/sbus/sbusvar.h>
+
+#include <dev/gem/if_gemreg.h>
+#include <dev/gem/if_gemvar.h>
+
+#include "miibus_if.h"
+
+static device_probe_t gem_sbus_probe;
+static device_attach_t gem_sbus_attach;
+static device_detach_t gem_sbus_detach;
+static device_suspend_t gem_sbus_suspend;
+static device_resume_t gem_sbus_resume;
+
+static device_method_t gem_sbus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gem_sbus_probe),
+	DEVMETHOD(device_attach,	gem_sbus_attach),
+	DEVMETHOD(device_detach,	gem_sbus_detach),
+	DEVMETHOD(device_suspend,	gem_sbus_suspend),
+	DEVMETHOD(device_resume,	gem_sbus_resume),
+	/* Use the suspend handler here, it is all that is required. */
+	DEVMETHOD(device_shutdown,	gem_sbus_suspend),
+
+	/* bus interface */
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	gem_mii_readreg),
+	DEVMETHOD(miibus_writereg,	gem_mii_writereg),
+	DEVMETHOD(miibus_statchg,	gem_mii_statchg),
+
+	KOBJMETHOD_END
+};
+
+static driver_t gem_sbus_driver = {
+	"gem",
+	gem_sbus_methods,
+	sizeof(struct gem_softc)
+};
+
+DRIVER_MODULE(gem, sbus, gem_sbus_driver, gem_devclass, 0, 0);
+MODULE_DEPEND(gem, sbus, 1, 1, 1);
+MODULE_DEPEND(gem, ether, 1, 1, 1);
+
+static int
+gem_sbus_probe(device_t dev)
+{
+
+	if (strcmp(ofw_bus_get_name(dev), "network") == 0 &&
+	    ofw_bus_get_compat(dev) != NULL &&
+	    strcmp(ofw_bus_get_compat(dev), "SUNW,sbus-gem") == 0) {
+		device_set_desc(dev, "Sun GEM Gigabit Ethernet");
+		return (0);
+	}
+
+	return (ENXIO);
+}
+
+static struct resource_spec gem_sbus_res_spec[] = {
+	{ SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE },	/* GEM_RES_INTR */
+	{ SYS_RES_MEMORY, 1, RF_ACTIVE },		/* GEM_RES_BANK1 */
+	{ SYS_RES_MEMORY, 0, RF_ACTIVE },		/* GEM_RES_BANK2 */
+	{ -1, 0 }
+};
+
+static int
+gem_sbus_attach(device_t dev)
+{
+	struct gem_softc *sc;
+	int burst;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+	sc->sc_variant = GEM_SUN_GEM;
+	sc->sc_dev = dev;
+
+	if (bus_alloc_resources(dev, gem_sbus_res_spec, sc->sc_res)) {
+		device_printf(dev, "failed to allocate resources\n");
+		bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res);
+		return (ENXIO);
+	}
+
+	GEM_LOCK_INIT(sc, device_get_nameunit(dev));
+
+	OF_getetheraddr(dev, sc->sc_enaddr);
+
+	burst = sbus_get_burstsz(dev);
+	val = GEM_SBUS_CFG_PARITY;
+	if ((burst & SBUS_BURST64_MASK) != 0) {
+		val |= GEM_SBUS_CFG_64BIT;
+		burst >>= SBUS_BURST64_SHIFT;
+	}
+	if ((burst & SBUS_BURST_64) != 0)
+		val |= GEM_SBUS_CFG_BURST_64;
+	else if ((burst & SBUS_BURST_32) != 0)
+		val |= GEM_SBUS_CFG_BURST_32;
+	else {
+		device_printf(dev, "unsupported burst size\n");
+		goto fail;
+	}
+	/* Reset the SBus interface only. */
+	(void)GEM_BANK2_READ_4(sc, GEM_SBUS_BIF_RESET);
+	DELAY(100);
+	GEM_BANK2_WRITE_4(sc, GEM_SBUS_CONFIG, val);
+
+	if (gem_attach(sc) != 0) {
+		device_printf(dev, "could not be attached\n");
+		goto fail;
+	}
+
+	if (bus_setup_intr(dev, sc->sc_res[GEM_RES_INTR], INTR_TYPE_NET |
+	    INTR_MPSAFE, NULL, gem_intr, sc, &sc->sc_ih) != 0) {
+		device_printf(dev, "failed to set up interrupt\n");
+		gem_detach(sc);
+		goto fail;
+	}
+	return (0);
+
+ fail:
+	GEM_LOCK_DESTROY(sc);
+	bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res);
+	return (ENXIO);
+}
+
+static int
+gem_sbus_detach(device_t dev)
+{
+	struct gem_softc *sc;
+
+	sc = device_get_softc(dev);
+	bus_teardown_intr(dev, sc->sc_res[GEM_RES_INTR], sc->sc_ih);
+	gem_detach(sc);
+	GEM_LOCK_DESTROY(sc);
+	bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res);
+	return (0);
+}
+
+static int
+gem_sbus_suspend(device_t dev)
+{
+
+	gem_suspend(device_get_softc(dev));
+	return (0);
+}
+
+static int
+gem_sbus_resume(device_t dev)
+{
+
+	gem_resume(device_get_softc(dev));
+	return (0);
+}

Modified: head/sys/dev/gem/if_gemreg.h
==============================================================================
--- head/sys/dev/gem/if_gemreg.h	Tue Jun 23 20:35:51 2009	(r194762)
+++ head/sys/dev/gem/if_gemreg.h	Tue Jun 23 20:36:59 2009	(r194763)
@@ -32,7 +32,7 @@
 #ifndef	_IF_GEMREG_H
 #define	_IF_GEMREG_H
 
-/* Register definitions for Sun GEM gigabit ethernet */
+/* register definitions for Apple GMAC, Sun ERI and Sun GEM */
 
 /*

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906232036.n5NKax9O089354>