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 <mar...@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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to