Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Sep 2009 12:56:50 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r197349 - in stable/7/sys: . conf contrib/pf dev/gem modules/gem
Message-ID:  <200909201256.n8KCuofu057064@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marius
Date: Sun Sep 20 12:56:50 2009
New Revision: 197349
URL: http://svn.freebsd.org/changeset/base/197349

Log:
  MFC: r194763, r194886
  
  - 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.
  - Call ether_ifdetach(9) before stopping the controller and the
    callouts. The consensus is that the latter is now safe to do and
    should also solve the problem of active BPF listeners clearing
    promiscuous mode can result in the tick callout being restarted
    which in turn will trigger a panic once it's actually gone.
  - 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.
  
  Obtained from:	NetBSD (partially) [2], OpenBSD [1]

Added:
  stable/7/sys/dev/gem/if_gem_sbus.c
     - copied unchanged from r194763, head/sys/dev/gem/if_gem_sbus.c
Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/conf/files
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/gem/if_gem.c
  stable/7/sys/dev/gem/if_gem_pci.c
  stable/7/sys/dev/gem/if_gemreg.h
  stable/7/sys/dev/gem/if_gemvar.h
  stable/7/sys/modules/gem/Makefile

Modified: stable/7/sys/conf/files
==============================================================================
--- stable/7/sys/conf/files	Sun Sep 20 12:40:56 2009	(r197348)
+++ stable/7/sys/conf/files	Sun Sep 20 12:56:50 2009	(r197349)
@@ -841,6 +841,7 @@ dev/flash/at45d.c		optional at45d
 dev/fxp/if_fxp.c		optional fxp
 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: stable/7/sys/dev/gem/if_gem.c
==============================================================================
--- stable/7/sys/dev/gem/if_gem.c	Sun Sep 20 12:40:56 2009	(r197348)
+++ stable/7/sys/dev/gem/if_gem.c	Sun Sep 20 12:56:50 2009	(r197349)
@@ -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);
 
@@ -401,6 +403,7 @@ gem_detach(struct gem_softc *sc)
 	struct ifnet *ifp = sc->sc_ifp;
 	int i;
 
+	ether_ifdetach(ifp);
 	GEM_LOCK(sc);
 	gem_stop(ifp, 1);
 	GEM_UNLOCK(sc);
@@ -408,7 +411,6 @@ gem_detach(struct gem_softc *sc)
 #ifdef GEM_RINT_TIMEOUT
 	callout_drain(&sc->sc_rx_ch);
 #endif
-	ether_ifdetach(ifp);
 	if_free(ifp);
 	device_delete_child(sc->sc_dev, sc->sc_miibus);
 
@@ -456,7 +458,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 +537,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 +585,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 +594,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 +644,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 +720,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 +731,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 +799,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 +839,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 +941,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 +966,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 +979,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 +992,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 +1023,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 +1058,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 +1166,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 +1197,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 +1206,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 +1236,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 +1258,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 +1277,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 +1314,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 +1326,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 +1358,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 +1375,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 +1455,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 +1473,7 @@ gem_rint_timeout(void *arg)
 	struct gem_softc *sc = arg;
 
 	GEM_LOCK_ASSERT(sc, MA_OWNED);
+
 	gem_rint(sc);
 }
 #endif
@@ -1449,6 +1486,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 +1500,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 +1563,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 +1583,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 +1597,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 +1610,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 +1660,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 +1682,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 +1713,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 +1723,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 +1957,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 +2038,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

Modified: stable/7/sys/dev/gem/if_gem_pci.c
==============================================================================
--- stable/7/sys/dev/gem/if_gem_pci.c	Sun Sep 20 12:40:56 2009	(r197348)
+++ stable/7/sys/dev/gem/if_gem_pci.c	Sun Sep 20 12:56:50 2009	(r197349)
@@ -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);
 }

Copied: stable/7/sys/dev/gem/if_gem_sbus.c (from r194763, head/sys/dev/gem/if_gem_sbus.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/dev/gem/if_gem_sbus.c	Sun Sep 20 12:56:50 2009	(r197349, copy of r194763, head/sys/dev/gem/if_gem_sbus.c)
@@ -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: stable/7/sys/dev/gem/if_gemreg.h
==============================================================================
--- stable/7/sys/dev/gem/if_gemreg.h	Sun Sep 20 12:40:56 2009	(r197348)
+++ stable/7/sys/dev/gem/if_gemreg.h	Sun Sep 20 12:56:50 2009	(r197349)
@@ -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 */
 
 /*
  * First bank: this registers live at the start of the PCI
@@ -47,97 +47,110 @@
 #define	GEM_INTACK		0x0014	/* Interrupt acknowledge, W/O */
 #define	GEM_STATUS_ALIAS	0x001c

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



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