Module Name:    src
Committed By:   dyoung
Date:           Mon Jul 27 18:10:54 UTC 2009

Modified Files:
        src/sys/dev/ic: gem.c gemvar.h
        src/sys/dev/pci: if_gem_pci.c
        src/sys/dev/sbus: if_gem_sbus.c

Log Message:
Do a complete device_t/softc split for the PCI attachment.  I have
not finished the device_t/softc split for the SBus attachment
because I don't have an SBus gem(4) to test with.

Convert from legacy shutdownhooks to a PMF shutdown hook.  Add PMF
suspend/resume handlers.

Factor a detachment hook out of gem_attach().  During device
attachment, track which resources are reserved in sc_attach_state,
and release only those resources during detachment.

Tested on gem0 and gem1 at pci1 on a Sun Fire V120.


To generate a diff of this commit:
cvs rdiff -u -r1.84 -r1.85 src/sys/dev/ic/gem.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/ic/gemvar.h
cvs rdiff -u -r1.35 -r1.36 src/sys/dev/pci/if_gem_pci.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/sbus/if_gem_sbus.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/gem.c
diff -u src/sys/dev/ic/gem.c:1.84 src/sys/dev/ic/gem.c:1.85
--- src/sys/dev/ic/gem.c:1.84	Tue May 12 14:25:17 2009
+++ src/sys/dev/ic/gem.c	Mon Jul 27 18:10:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: gem.c,v 1.84 2009/05/12 14:25:17 cegger Exp $ */
+/*	$NetBSD: gem.c,v 1.85 2009/07/27 18:10:53 dyoung Exp $ */
 
 /*
  *
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.84 2009/05/12 14:25:17 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.85 2009/07/27 18:10:53 dyoung Exp $");
 
 #include "opt_inet.h"
 #include "bpfilter.h"
@@ -88,12 +88,12 @@
 
 #define TRIES	10000
 
+static void	gem_inten(struct gem_softc *);
 static void	gem_start(struct ifnet *);
 static void	gem_stop(struct ifnet *, int);
 int		gem_ioctl(struct ifnet *, u_long, void *);
 void		gem_tick(void *);
 void		gem_watchdog(struct ifnet *);
-void		gem_shutdown(void *);
 void		gem_pcs_start(struct gem_softc *sc);
 void		gem_pcs_stop(struct gem_softc *sc, int);
 int		gem_init(struct ifnet *);
@@ -126,6 +126,8 @@
 int		gem_ser_mediachange(struct ifnet *);
 void		gem_ser_mediastatus(struct ifnet *, struct ifmediareq *);
 
+static void	gem_partial_detach(struct gem_softc *, enum gem_attach_stage);
+
 struct mbuf	*gem_get(struct gem_softc *, int, int);
 int		gem_put(struct gem_softc *, int, struct mbuf *);
 void		gem_read(struct gem_softc *, int, int);
@@ -145,6 +147,97 @@
 
 #define ETHER_MIN_TX (ETHERMIN + sizeof(struct ether_header))
 
+int
+gem_detach(struct gem_softc *sc, int flags)
+{
+	char *nullbuf;
+	int i, rc;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+
+	nullbuf =
+	    (char *)sc->sc_control_data + sizeof(struct gem_control_data);
+
+	/*
+	 * Free any resources we've allocated during the attach.
+	 * Do this in reverse order and fall through.
+	 */
+	switch (sc->sc_att_stage) {
+	case GEM_ATT_BACKEND_2:
+	case GEM_ATT_BACKEND_1:
+	case GEM_ATT_FINISHED:
+		gem_stop(&sc->sc_ethercom.ec_if, 1);
+
+#ifdef GEM_COUNTERS
+		for (i = __arraycount(sc->sc_ev_rxhist); --i >= 0; )
+			evcnt_detach(&sc->sc_ev_rxhist[i]);
+		evcnt_detach(&sc->sc_ev_rxnobuf);
+		evcnt_detach(&sc->sc_ev_rxfull);
+		evcnt_detach(&sc->sc_ev_rxint);
+		evcnt_detach(&sc->sc_ev_txint);
+#endif
+		evcnt_detach(&sc->sc_ev_intr);
+
+		callout_destroy(&sc->sc_tick_ch);
+#if NRND > 0
+		rnd_detach_source(&sc->rnd_source);
+#endif
+		ether_ifdetach(ifp);
+		if_detach(ifp);
+		ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
+		/*FALLTHROUGH*/
+	case GEM_ATT_MII:
+		sc->sc_att_stage = GEM_ATT_MII;
+		if ((rc = config_detach_children(sc->sc_dev, flags)) != 0)
+			return rc;
+		/*FALLTHROUGH*/
+	case GEM_ATT_7:
+		for (i = 0; i < GEM_NRXDESC; i++) {
+			if (sc->sc_rxsoft[i].rxs_dmamap != NULL)
+				bus_dmamap_destroy(sc->sc_dmatag,
+				    sc->sc_rxsoft[i].rxs_dmamap);
+		}
+		/*FALLTHROUGH*/
+	case GEM_ATT_6:
+		for (i = 0; i < GEM_TXQUEUELEN; i++) {
+			if (sc->sc_txsoft[i].txs_dmamap != NULL)
+				bus_dmamap_destroy(sc->sc_dmatag,
+				    sc->sc_txsoft[i].txs_dmamap);
+		}
+		bus_dmamap_unload(sc->sc_dmatag, sc->sc_cddmamap);
+		/*FALLTHROUGH*/
+	case GEM_ATT_5:
+		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_nulldmamap);
+		/*FALLTHROUGH*/
+	case GEM_ATT_4:
+		bus_dmamem_unmap(sc->sc_dmatag, nullbuf, ETHER_MIN_TX);
+		/*FALLTHROUGH*/
+	case GEM_ATT_3:
+		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cddmamap);
+		/*FALLTHROUGH*/
+	case GEM_ATT_2:
+		bus_dmamem_unmap(sc->sc_dmatag, sc->sc_control_data,
+		    sizeof(struct gem_control_data));
+		/*FALLTHROUGH*/
+	case GEM_ATT_1:
+		bus_dmamem_free(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg);
+		/*FALLTHROUGH*/
+	case GEM_ATT_0:
+		sc->sc_att_stage = GEM_ATT_0;
+		/*FALLTHROUGH*/
+	case GEM_ATT_BACKEND_0:
+		break;
+	}
+	return 0;
+}
+
+static void
+gem_partial_detach(struct gem_softc *sc, enum gem_attach_stage stage)
+{
+	cfattach_t ca = device_cfattach(sc->sc_dev);
+
+	sc->sc_att_stage = stage;
+	(*ca->ca_detach)(sc->sc_dev, 0);
+}
 
 /*
  * gem_attach:
@@ -175,19 +268,21 @@
 	if ((error = bus_dmamem_alloc(sc->sc_dmatag,
 	    sizeof(struct gem_control_data) + ETHER_MIN_TX, PAGE_SIZE,
 	    0, &sc->sc_cdseg, 1, &sc->sc_cdnseg, 0)) != 0) {
-		aprint_error_dev(&sc->sc_dev,
+		aprint_error_dev(sc->sc_dev,
 		   "unable to allocate control data, error = %d\n",
 		    error);
-		goto fail_0;
+		gem_partial_detach(sc, GEM_ATT_0);
+		return;
 	}
 
 	/* XXX should map this in with correct endianness */
 	if ((error = bus_dmamem_map(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg,
 	    sizeof(struct gem_control_data), (void **)&sc->sc_control_data,
 	    BUS_DMA_COHERENT)) != 0) {
-		aprint_error_dev(&sc->sc_dev, "unable to map control data, error = %d\n",
-		    error);
-		goto fail_1;
+		aprint_error_dev(sc->sc_dev,
+		    "unable to map control data, error = %d\n", error);
+		gem_partial_detach(sc, GEM_ATT_1);
+		return;
 	}
 
 	nullbuf =
@@ -196,34 +291,38 @@
 	if ((error = bus_dmamap_create(sc->sc_dmatag,
 	    sizeof(struct gem_control_data), 1,
 	    sizeof(struct gem_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
-		aprint_error_dev(&sc->sc_dev, "unable to create control data DMA map, "
-		    "error = %d\n", error);
-		goto fail_2;
+		aprint_error_dev(sc->sc_dev,
+		    "unable to create control data DMA map, error = %d\n",
+		    error);
+		gem_partial_detach(sc, GEM_ATT_2);
+		return;
 	}
 
 	if ((error = bus_dmamap_load(sc->sc_dmatag, sc->sc_cddmamap,
 	    sc->sc_control_data, sizeof(struct gem_control_data), NULL,
 	    0)) != 0) {
-		aprint_error_dev(&sc->sc_dev,
+		aprint_error_dev(sc->sc_dev,
 		    "unable to load control data DMA map, error = %d\n",
 		    error);
-		goto fail_3;
+		gem_partial_detach(sc, GEM_ATT_3);
+		return;
 	}
 
 	memset(nullbuf, 0, ETHER_MIN_TX);
 	if ((error = bus_dmamap_create(sc->sc_dmatag,
 	    ETHER_MIN_TX, 1, ETHER_MIN_TX, 0, 0, &sc->sc_nulldmamap)) != 0) {
-		aprint_error_dev(&sc->sc_dev, "unable to create padding DMA map, "
-		    "error = %d\n", error);
-		goto fail_4;
+		aprint_error_dev(sc->sc_dev,
+		    "unable to create padding DMA map, error = %d\n", error);
+		gem_partial_detach(sc, GEM_ATT_4);
+		return;
 	}
 
 	if ((error = bus_dmamap_load(sc->sc_dmatag, sc->sc_nulldmamap,
 	    nullbuf, ETHER_MIN_TX, NULL, 0)) != 0) {
-		aprint_error_dev(&sc->sc_dev,
-		    "unable to load padding DMA map, error = %d\n",
-		    error);
-		goto fail_5;
+		aprint_error_dev(sc->sc_dev,
+		    "unable to load padding DMA map, error = %d\n", error);
+		gem_partial_detach(sc, GEM_ATT_5);
+		return;
 	}
 
 	bus_dmamap_sync(sc->sc_dmatag, sc->sc_nulldmamap, 0, ETHER_MIN_TX,
@@ -247,9 +346,11 @@
 		    ETHER_MAX_LEN_JUMBO, GEM_NTXSEGS,
 		    ETHER_MAX_LEN_JUMBO, 0, 0,
 		    &txs->txs_dmamap)) != 0) {
-			aprint_error_dev(&sc->sc_dev, "unable to create tx DMA map %d, "
-			    "error = %d\n", i, error);
-			goto fail_6;
+			aprint_error_dev(sc->sc_dev,
+			    "unable to create tx DMA map %d, error = %d\n",
+			    i, error);
+			gem_partial_detach(sc, GEM_ATT_6);
+			return;
 		}
 		SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
 	}
@@ -260,9 +361,11 @@
 	for (i = 0; i < GEM_NRXDESC; i++) {
 		if ((error = bus_dmamap_create(sc->sc_dmatag, MCLBYTES, 1,
 		    MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
-			aprint_error_dev(&sc->sc_dev, "unable to create rx DMA map %d, "
-			    "error = %d\n", i, error);
-			goto fail_7;
+			aprint_error_dev(sc->sc_dev,
+			    "unable to create rx DMA map %d, error = %d\n",
+			    i, error);
+			gem_partial_detach(sc, GEM_ATT_7);
+			return;
 		}
 		sc->sc_rxsoft[i].rxs_mbuf = NULL;
 	}
@@ -290,12 +393,14 @@
 	if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0) {
 		ifmedia_init(&mii->mii_media, IFM_IMASK, ether_mediachange,
 		    ether_mediastatus);
-		mii_attach(&sc->sc_dev, mii, 0xffffffff,
+		mii_attach(sc->sc_dev, mii, 0xffffffff,
 		    MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG);
 		if (LIST_EMPTY(&mii->mii_phys)) {
 				/* No PHY attached */
-				aprint_error_dev(&sc->sc_dev, "PHY probe failed\n");
-				goto fail_7;
+				aprint_error_dev(sc->sc_dev,
+				    "PHY probe failed\n");
+				gem_partial_detach(sc, GEM_ATT_MII);
+				return;
 		} else {
 			struct mii_softc *child;
 
@@ -311,7 +416,7 @@
 				 * by the GEM_MIF_CONFIG  register.
 				 */
 				if (child->mii_phy > 1 || child->mii_inst > 0) {
-					aprint_error_dev(&sc->sc_dev,
+					aprint_error_dev(sc->sc_dev,
 					    "cannot accommodate MII device"
 					    " %s at PHY %d, instance %d\n",
 					       device_xname(child->mii_dev),
@@ -329,12 +434,14 @@
 			 */
 			if (sc->sc_phys[1]) {
 #ifdef GEM_DEBUG
-				aprint_debug_dev(&sc->sc_dev, "using external PHY\n");
+				aprint_debug_dev(sc->sc_dev,
+				    "using external PHY\n");
 #endif
 				sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL;
 			} else {
 #ifdef GEM_DEBUG
-				aprint_debug_dev(&sc->sc_dev, "using internal PHY\n");
+				aprint_debug_dev(sc->sc_dev,
+				    "using internal PHY\n");
 				sc->sc_mif_config &= ~GEM_MIF_CONFIG_PHY_SEL;
 #endif
 			}
@@ -363,7 +470,7 @@
 			    GEM_MII_DATAPATH_SERIAL);
 		}
 
-		aprint_normal_dev(&sc->sc_dev, "using external PCS %s: ",
+		aprint_normal_dev(sc->sc_dev, "using external PCS %s: ",
 		    sc->sc_flags & GEM_SERDES ? "SERDES" : "Serialink");
 
 		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO, 0, NULL);
@@ -393,7 +500,7 @@
 	 */
 
 	/* Announce ourselves. */
-	aprint_normal_dev(&sc->sc_dev, "Ethernet address %s",
+	aprint_normal_dev(sc->sc_dev, "Ethernet address %s",
 	    ether_sprintf(enaddr));
 
 	/* Get RX FIFO size */
@@ -406,20 +513,22 @@
 	aprint_normal(", %uKB TX fifo\n", v / 16);
 
 	/* Initialize ifnet structure. */
-	strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
+	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
 	ifp->if_softc = sc;
 	ifp->if_flags =
 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
 	sc->sc_if_flags = ifp->if_flags;
+#if 0
 	/*
 	 * The GEM hardware supports basic TCP checksum offloading only.
 	 * Several (all?) revisions (Sun rev. 01 and Apple rev. 00 and 80)
 	 * have bugs in the receive checksum, so don't enable it for now.
+	 */
 	if ((GEM_IS_SUN(sc) && sc->sc_chiprev != 1) ||
 	    (GEM_IS_APPLE(sc) &&
 	    (sc->sc_chiprev != 0 && sc->sc_chiprev != 0x80)))
 		ifp->if_capabilities |= IFCAP_CSUM_TCPv4_Rx;
-	*/
+#endif
 	ifp->if_capabilities |= IFCAP_CSUM_TCPv4_Tx;
 	ifp->if_start = gem_start;
 	ifp->if_ioctl = gem_ioctl;
@@ -453,93 +562,49 @@
 	ether_ifattach(ifp, enaddr);
 	ether_set_ifflags_cb(&sc->sc_ethercom, gem_ifflags_cb);
 
-	sc->sc_sh = shutdownhook_establish(gem_shutdown, sc);
-	if (sc->sc_sh == NULL)
-		panic("gem_config: can't establish shutdownhook");
-
 #if NRND > 0
-	rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dev),
+	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
 			  RND_TYPE_NET, 0);
 #endif
 
 	evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR,
-	    NULL, device_xname(&sc->sc_dev), "interrupts");
+	    NULL, device_xname(sc->sc_dev), "interrupts");
 #ifdef GEM_COUNTERS
 	evcnt_attach_dynamic(&sc->sc_ev_txint, EVCNT_TYPE_INTR,
-	    &sc->sc_ev_intr, device_xname(&sc->sc_dev), "tx interrupts");
+	    &sc->sc_ev_intr, device_xname(sc->sc_dev), "tx interrupts");
 	evcnt_attach_dynamic(&sc->sc_ev_rxint, EVCNT_TYPE_INTR,
-	    &sc->sc_ev_intr, device_xname(&sc->sc_dev), "rx interrupts");
+	    &sc->sc_ev_intr, device_xname(sc->sc_dev), "rx interrupts");
 	evcnt_attach_dynamic(&sc->sc_ev_rxfull, EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx ring full");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx ring full");
 	evcnt_attach_dynamic(&sc->sc_ev_rxnobuf, EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx malloc failure");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx malloc failure");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[0], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx 0desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx 0desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[1], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx 1desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx 1desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[2], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx 2desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx 2desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[3], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx 3desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx 3desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[4], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx >3desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx >3desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[5], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx >7desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx >7desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[6], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx >15desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx >15desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[7], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx >31desc");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx >31desc");
 	evcnt_attach_dynamic(&sc->sc_ev_rxhist[8], EVCNT_TYPE_INTR,
-	    &sc->sc_ev_rxint, device_xname(&sc->sc_dev), "rx >63desc");
-#endif
-
-#if notyet
-	/*
-	 * Add a suspend hook to make sure we come back up after a
-	 * resume.
-	 */
-	sc->sc_powerhook = powerhook_establish(device_xname(&sc->sc_dev),
-	    gem_power, sc);
-	if (sc->sc_powerhook == NULL)
-		aprint_error_dev(&sc->sc_dev, "WARNING: unable to establish power hook\n");
+	    &sc->sc_ev_rxint, device_xname(sc->sc_dev), "rx >63desc");
 #endif
 
 	callout_init(&sc->sc_tick_ch, 0);
-	return;
 
-	/*
-	 * Free any resources we've allocated during the failed attach
-	 * attempt.  Do this in reverse order and fall through.
-	 */
- fail_7:
-	for (i = 0; i < GEM_NRXDESC; i++) {
-		if (sc->sc_rxsoft[i].rxs_dmamap != NULL)
-			bus_dmamap_destroy(sc->sc_dmatag,
-			    sc->sc_rxsoft[i].rxs_dmamap);
-	}
- fail_6:
-	for (i = 0; i < GEM_TXQUEUELEN; i++) {
-		if (sc->sc_txsoft[i].txs_dmamap != NULL)
-			bus_dmamap_destroy(sc->sc_dmatag,
-			    sc->sc_txsoft[i].txs_dmamap);
-	}
-	bus_dmamap_unload(sc->sc_dmatag, sc->sc_cddmamap);
- fail_5:
-	bus_dmamap_destroy(sc->sc_dmatag, sc->sc_nulldmamap);
- fail_4:
-	bus_dmamem_unmap(sc->sc_dmatag, (void *)nullbuf, ETHER_MIN_TX);
- fail_3:
-	bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cddmamap);
- fail_2:
-	bus_dmamem_unmap(sc->sc_dmatag, (void *)sc->sc_control_data,
-	    sizeof(struct gem_control_data));
- fail_1:
-	bus_dmamem_free(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg);
- fail_0:
+	sc->sc_att_stage = GEM_ATT_FINISHED;
+
 	return;
 }
 
-
 void
 gem_tick(void *arg)
 {
@@ -583,14 +648,14 @@
 	int s;
 
 	s = splnet();
-	DPRINTF(sc, ("%s: gem_reset\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_reset\n", device_xname(sc->sc_dev)));
 	gem_reset_rx(sc);
 	gem_reset_tx(sc);
 
 	/* Do a full reset */
 	bus_space_write_4(t, h, GEM_RESET, GEM_RESET_RX|GEM_RESET_TX);
 	if (!gem_bitwait(sc, h, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0))
-		aprint_error_dev(&sc->sc_dev, "cannot reset device\n");
+		aprint_error_dev(sc->sc_dev, "cannot reset device\n");
 	splx(s);
 }
 
@@ -624,10 +689,10 @@
 static void
 gem_stop(struct ifnet *ifp, int disable)
 {
-	struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
+	struct gem_softc *sc = ifp->if_softc;
 	struct gem_txsoft *txs;
 
-	DPRINTF(sc, ("%s: gem_stop\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_stop\n", device_xname(sc->sc_dev)));
 
 	callout_stop(&sc->sc_tick_ch);
 	if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0)
@@ -684,14 +749,14 @@
 	bus_space_barrier(t, h, GEM_RX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE);
 	/* Wait till it finishes */
 	if (!gem_bitwait(sc, h, GEM_RX_CONFIG, 1, 0))
-		aprint_error_dev(&sc->sc_dev, "cannot disable read dma\n");
+		aprint_error_dev(sc->sc_dev, "cannot disable read dma\n");
 
 	/* Finally, reset the ERX */
 	bus_space_write_4(t, h2, GEM_RESET, GEM_RESET_RX);
 	bus_space_barrier(t, h, GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE);
 	/* Wait till it finishes */
 	if (!gem_bitwait(sc, h2, GEM_RESET, GEM_RESET_RX, 0)) {
-		aprint_error_dev(&sc->sc_dev, "cannot reset receiver\n");
+		aprint_error_dev(sc->sc_dev, "cannot reset receiver\n");
 		return (1);
 	}
 	return (0);
@@ -790,7 +855,7 @@
 	bus_space_barrier(t, h, GEM_TX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE);
 	/* Wait till it finishes */
 	if (!gem_bitwait(sc, h, GEM_TX_CONFIG, 1, 0))
-		aprint_error_dev(&sc->sc_dev, "cannot disable read dma\n");
+		aprint_error_dev(sc->sc_dev, "cannot disable read dma\n");
 	/* Wait 5ms extra. */
 	delay(5000);
 
@@ -799,7 +864,7 @@
 	bus_space_barrier(t, h, GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE);
 	/* Wait till it finishes */
 	if (!gem_bitwait(sc, h2, GEM_RESET, GEM_RESET_TX, 0)) {
-		aprint_error_dev(&sc->sc_dev, "cannot reset receiver\n");
+		aprint_error_dev(sc->sc_dev, "cannot reset receiver\n");
 		return (1);
 	}
 	return (0);
@@ -855,7 +920,7 @@
 	/*
 	 * Initialize the transmit descriptor ring.
 	 */
-	memset((void *)sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
+	memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
 	for (i = 0; i < GEM_NTXDESC; i++) {
 		sc->sc_txdescs[i].gd_flags = 0;
 		sc->sc_txdescs[i].gd_addr = 0;
@@ -874,7 +939,8 @@
 		rxs = &sc->sc_rxsoft[i];
 		if (rxs->rxs_mbuf == NULL) {
 			if ((error = gem_add_rxbuf(sc, i)) != 0) {
-				aprint_error_dev(&sc->sc_dev, "unable to allocate or map rx "
+				aprint_error_dev(sc->sc_dev,
+				    "unable to allocate or map rx "
 				    "buffer %d, error = %d\n",
 				    i, error);
 				/*
@@ -935,7 +1001,7 @@
 	uint32_t v;
 
 #ifdef GEM_DEBUG
-	aprint_debug_dev(&sc->sc_dev, "gem_pcs_start()\n");
+	aprint_debug_dev(sc->sc_dev, "gem_pcs_start()\n");
 #endif
 
 	/*
@@ -986,7 +1052,7 @@
 	bus_space_handle_t h = sc->sc_h1;
 
 #ifdef GEM_DEBUG
-	aprint_debug_dev(&sc->sc_dev, "gem_pcs_stop()\n");
+	aprint_debug_dev(sc->sc_dev, "gem_pcs_stop()\n");
 #endif
 
 	/* Tell link partner that we're going away */
@@ -1026,7 +1092,7 @@
 int
 gem_init(struct ifnet *ifp)
 {
-	struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
+	struct gem_softc *sc = ifp->if_softc;
 	bus_space_tag_t t = sc->sc_bustag;
 	bus_space_handle_t h = sc->sc_h1;
 	int rc = 0, s;
@@ -1035,7 +1101,7 @@
 
 	s = splnet();
 
-	DPRINTF(sc, ("%s: gem_init: calling stop\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_init: calling stop\n", device_xname(sc->sc_dev)));
 	/*
 	 * Initialization sequence. The numbered steps below correspond
 	 * to the sequence outlined in section 6.3.5.1 in the Ethernet
@@ -1046,7 +1112,7 @@
 	/* step 1 & 2. Reset the Ethernet Channel */
 	gem_stop(ifp, 0);
 	gem_reset(sc);
-	DPRINTF(sc, ("%s: gem_init: restarting\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_init: restarting\n", device_xname(sc->sc_dev)));
 
 	/* Re-initialize the MIF */
 	gem_mifinit(sc);
@@ -1086,17 +1152,7 @@
 	bus_space_write_4(t, h, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0));
 
 	/* step 8. Global Configuration & Interrupt Mask */
-	if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0)
-		v = GEM_INTR_PCS;
-	else
-		v = GEM_INTR_MIF;
-	bus_space_write_4(t, h, GEM_INTMASK,
-		      ~(GEM_INTR_TX_INTME |
-			GEM_INTR_TX_EMPTY |
-			GEM_INTR_TX_MAC |
-			GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF|
-			GEM_INTR_RX_TAG_ERR | GEM_INTR_MAC_CONTROL|
-			GEM_INTR_BERR | v));
+	gem_inten(sc);
 	bus_space_write_4(t, h, GEM_MAC_RX_MASK,
 			GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT);
 	bus_space_write_4(t, h, GEM_MAC_TX_MASK, 0xffff); /* XXX */
@@ -1277,7 +1333,7 @@
 static void
 gem_start(struct ifnet *ifp)
 {
-	struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
+	struct gem_softc *sc = ifp->if_softc;
 	struct mbuf *m0, *m;
 	struct gem_txsoft *txs;
 	bus_dmamap_t dmamap;
@@ -1295,7 +1351,7 @@
 	firsttx = sc->sc_txnext;
 
 	DPRINTF(sc, ("%s: gem_start: txfree %d, txnext %d\n",
-	    device_xname(&sc->sc_dev), ofree, firsttx));
+	    device_xname(sc->sc_dev), ofree, firsttx));
 
 	/*
 	 * Loop through the send queue, setting up transmit descriptors
@@ -1325,23 +1381,24 @@
 		      (m0->m_pkthdr.len < ETHER_MIN_TX &&
 		       dmamap->dm_nsegs == GEM_NTXSEGS)) {
 			if (m0->m_pkthdr.len > MCLBYTES) {
-				aprint_error_dev(&sc->sc_dev, "unable to allocate jumbo Tx "
-				    "cluster\n");
+				aprint_error_dev(sc->sc_dev,
+				    "unable to allocate jumbo Tx cluster\n");
 				IFQ_DEQUEUE(&ifp->if_snd, m0);
 				m_freem(m0);
 				continue;
 			}
 			MGETHDR(m, M_DONTWAIT, MT_DATA);
 			if (m == NULL) {
-				aprint_error_dev(&sc->sc_dev, "unable to allocate Tx mbuf\n");
+				aprint_error_dev(sc->sc_dev,
+				    "unable to allocate Tx mbuf\n");
 				break;
 			}
 			MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
 			if (m0->m_pkthdr.len > MHLEN) {
 				MCLGET(m, M_DONTWAIT);
 				if ((m->m_flags & M_EXT) == 0) {
-					aprint_error_dev(&sc->sc_dev, "unable to allocate Tx "
-					    "cluster\n");
+					aprint_error_dev(sc->sc_dev,
+					    "unable to allocate Tx cluster\n");
 					m_freem(m);
 					break;
 				}
@@ -1351,8 +1408,9 @@
 			error = bus_dmamap_load_mbuf(sc->sc_dmatag, dmamap,
 			    m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
 			if (error) {
-				aprint_error_dev(&sc->sc_dev, "unable to load Tx buffer, "
-				    "error = %d\n", error);
+				aprint_error_dev(sc->sc_dev,
+				    "unable to load Tx buffer, error = %d\n",
+				    error);
 				break;
 			}
 		}
@@ -1523,20 +1581,20 @@
 
 	if (sc->sc_txfree != ofree) {
 		DPRINTF(sc, ("%s: packets enqueued, IC on %d, OWN on %d\n",
-		    device_xname(&sc->sc_dev), lasttx, firsttx));
+		    device_xname(sc->sc_dev), lasttx, firsttx));
 		/*
 		 * The entire packet chain is set up.
 		 * Kick the transmitter.
 		 */
 		DPRINTF(sc, ("%s: gem_start: kicking tx %d\n",
-			device_xname(&sc->sc_dev), nexttx));
+			device_xname(sc->sc_dev), nexttx));
 		bus_space_write_4(sc->sc_bustag, sc->sc_h1, GEM_TX_KICK,
 			sc->sc_txnext);
 
 		/* Set a watchdog timer in case the chip flakes out. */
 		ifp->if_timer = 5;
 		DPRINTF(sc, ("%s: gem_start: watchdog %d\n",
-			device_xname(&sc->sc_dev), ifp->if_timer));
+			device_xname(sc->sc_dev), ifp->if_timer));
 	}
 }
 
@@ -1554,7 +1612,7 @@
 	int progress = 0;
 	u_int32_t v;
 
-	DPRINTF(sc, ("%s: gem_tint\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_tint\n", device_xname(sc->sc_dev)));
 
 	/* Unload collision counters ... */
 	v = bus_space_read_4(t, mac, GEM_MAC_EXCESS_COLL_CNT) +
@@ -1658,7 +1716,7 @@
 		gem_start(ifp);
 	}
 	DPRINTF(sc, ("%s: gem_tint: watchdog %d\n",
-		device_xname(&sc->sc_dev), ifp->if_timer));
+		device_xname(sc->sc_dev), ifp->if_timer));
 
 	return (1);
 }
@@ -1678,7 +1736,7 @@
 	u_int32_t rxcomp;
 	int i, len, progress = 0;
 
-	DPRINTF(sc, ("%s: gem_rint\n", device_xname(&sc->sc_dev)));
+	DPRINTF(sc, ("%s: gem_rint\n", device_xname(sc->sc_dev)));
 
 	/*
 	 * Ignore spurious interrupt that sometimes occurs before
@@ -1724,7 +1782,8 @@
 
 		if (rxstat & GEM_RD_BAD_CRC) {
 			ifp->if_ierrors++;
-			aprint_error_dev(&sc->sc_dev, "receive error: CRC error\n");
+			aprint_error_dev(sc->sc_dev,
+			    "receive error: CRC error\n");
 			GEM_INIT_RXDESC(sc, i);
 			continue;
 		}
@@ -1871,7 +1930,7 @@
 #ifdef GEM_DEBUG
 			if (ifp->if_flags & IFF_DEBUG)
 				printf("%s: rint: ring wrap\n",
-				    device_xname(&sc->sc_dev));
+				    device_xname(sc->sc_dev));
 #endif
 		}
 		sc->sc_rxptr = i;
@@ -1951,8 +2010,8 @@
 	    m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
 	    BUS_DMA_READ|BUS_DMA_NOWAIT);
 	if (error) {
-		aprint_error_dev(&sc->sc_dev, "can't load rx DMA map %d, error = %d\n",
-		    idx, error);
+		aprint_error_dev(sc->sc_dev,
+		    "can't load rx DMA map %d, error = %d\n", idx, error);
 		panic("gem_add_rxbuf");	/* XXX */
 	}
 
@@ -1972,7 +2031,7 @@
 	u_int32_t r, v;
 
 	if ((status & GEM_INTR_MIF) != 0) {
-		printf("%s: XXXlink status changed\n", device_xname(&sc->sc_dev));
+		printf("%s: XXXlink status changed\n", device_xname(sc->sc_dev));
 		return (1);
 	}
 
@@ -1988,12 +2047,12 @@
 			r = GEM_SBUS_ERROR_STATUS;
 		bus_space_read_4(sc->sc_bustag, sc->sc_h2, r);
 		v = bus_space_read_4(sc->sc_bustag, sc->sc_h2, r);
-		aprint_error_dev(&sc->sc_dev, "bus error interrupt: 0x%02x\n",
+		aprint_error_dev(sc->sc_dev, "bus error interrupt: 0x%02x\n",
 		    v);
 		return (1);
 	}
 	snprintb(bits, sizeof(bits), GEM_INTR_BITS, status);
-	printf("%s: status=%s\n", device_xname(&sc->sc_dev), bits);
+	printf("%s: status=%s\n", device_xname(sc->sc_dev), bits);
 		
 	return (1);
 }
@@ -2051,16 +2110,16 @@
 		if (v & GEM_MII_ANEG_FUL_DUPLX) {
 			sc->sc_mii.mii_media_active |= IFM_FDX;
 #ifdef GEM_DEBUG
-			aprint_debug_dev(&sc->sc_dev, "link up: full duplex\n");
+			aprint_debug_dev(sc->sc_dev, "link up: full duplex\n");
 #endif
 		} else if (v & GEM_MII_ANEG_HLF_DUPLX) {
 			sc->sc_mii.mii_media_active |= IFM_HDX;
 #ifdef GEM_DEBUG
-			aprint_debug_dev(&sc->sc_dev, "link up: half duplex\n");
+			aprint_debug_dev(sc->sc_dev, "link up: half duplex\n");
 #endif
 		} else {
 #ifdef GEM_DEBUG
-			aprint_debug_dev(&sc->sc_dev, "duplex mismatch\n");
+			aprint_debug_dev(sc->sc_dev, "duplex mismatch\n");
 #endif
 		}
 		gem_statuschange(sc);
@@ -2071,7 +2130,7 @@
 		sc->sc_mii.mii_media_active = IFM_ETHER | IFM_NONE;
 		sc->sc_mii.mii_media_status = IFM_AVALID;
 #ifdef GEM_DEBUG
-			aprint_debug_dev(&sc->sc_dev, "link down\n");
+			aprint_debug_dev(sc->sc_dev, "link down\n");
 #endif
 		gem_statuschange(sc);
 
@@ -2086,7 +2145,7 @@
 int
 gem_intr(void *v)
 {
-	struct gem_softc *sc = (struct gem_softc *)v;
+	struct gem_softc *sc = v;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	bus_space_tag_t t = sc->sc_bustag;
 	bus_space_handle_t h = sc->sc_h1;
@@ -2105,7 +2164,7 @@
 	snprintb(bits, sizeof(bits), GEM_INTR_BITS, status);
 #endif
 	DPRINTF(sc, ("%s: gem_intr: cplt 0x%x status %s\n",
-		device_xname(&sc->sc_dev), (status >> 19), bits));
+		device_xname(sc->sc_dev), (status >> 19), bits));
 		
 
 	if ((status & (GEM_INTR_RX_TAG_ERR | GEM_INTR_BERR)) != 0)
@@ -2127,7 +2186,7 @@
 		int txstat = bus_space_read_4(t, h, GEM_MAC_TX_STATUS);
 		if (txstat & ~GEM_MAC_TX_XMIT_DONE)
 			printf("%s: MAC tx fault, status %x\n",
-			    device_xname(&sc->sc_dev), txstat);
+			    device_xname(sc->sc_dev), txstat);
 		if (txstat & (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG))
 			gem_init(ifp);
 	}
@@ -2144,7 +2203,7 @@
 			gem_reset_rxdma(sc);
 		} else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT))
 			printf("%s: MAC rx fault, status 0x%02x\n",
-			    device_xname(&sc->sc_dev), rxstat);
+			    device_xname(sc->sc_dev), rxstat);
 	}
 	if (status & GEM_INTR_PCS) {
 		r |= gem_pint(sc);
@@ -2154,15 +2213,15 @@
 	if ((status & GEM_MAC_CONTROL_STATUS) != 0) {
 		status2 = bus_read_4(sc->sc_res[0], GEM_MAC_CONTROL_STATUS);
 		if ((status2 & GEM_MAC_PAUSED) != 0)
-			aprintf_debug_dev(&sc->sc_dev, "PAUSE received (%d slots)\n",
+			aprintf_debug_dev(sc->sc_dev, "PAUSE received (%d slots)\n",
 			    GEM_MAC_PAUSE_TIME(status2));
 		if ((status2 & GEM_MAC_PAUSE) != 0)
-			aprintf_debug_dev(&sc->sc_dev, "transited to PAUSE state\n");
+			aprintf_debug_dev(sc->sc_dev, "transited to PAUSE state\n");
 		if ((status2 & GEM_MAC_RESUME) != 0)
-			aprintf_debug_dev(&sc->sc_dev, "transited to non-PAUSE state\n");
+			aprintf_debug_dev(sc->sc_dev, "transited to non-PAUSE state\n");
 	}
 	if ((status & GEM_INTR_MIF) != 0)
-		aprintf_debug_dev(&sc->sc_dev, "MIF interrupt\n");
+		aprintf_debug_dev(sc->sc_dev, "MIF interrupt\n");
 */
 #if NRND > 0
 	rnd_add_uint32(&sc->rnd_source, status);
@@ -2182,7 +2241,7 @@
 		bus_space_read_4(sc->sc_bustag, sc->sc_h1, GEM_MAC_RX_STATUS),
 		bus_space_read_4(sc->sc_bustag, sc->sc_h1, GEM_MAC_RX_CONFIG)));
 
-	log(LOG_ERR, "%s: device timeout\n", device_xname(&sc->sc_dev));
+	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
 	++ifp->if_oerrors;
 
 	/* Try to get more packets going. */
@@ -2221,7 +2280,7 @@
 static int
 gem_mii_readreg(device_t self, int phy, int reg)
 {
-	struct gem_softc *sc = (void *)self;
+	struct gem_softc *sc = device_private(self);
 	bus_space_tag_t t = sc->sc_bustag;
 	bus_space_handle_t mif = sc->sc_h1;
 	int n;
@@ -2244,14 +2303,14 @@
 			return (v & GEM_MIF_FRAME_DATA);
 	}
 
-	printf("%s: mii_read timeout\n", device_xname(&sc->sc_dev));
+	printf("%s: mii_read timeout\n", device_xname(sc->sc_dev));
 	return (0);
 }
 
 static void
 gem_mii_writereg(device_t self, int phy, int reg, int val)
 {
-	struct gem_softc *sc = (void *)self;
+	struct gem_softc *sc = device_private(self);
 	bus_space_tag_t t = sc->sc_bustag;
 	bus_space_handle_t mif = sc->sc_h1;
 	int n;
@@ -2277,13 +2336,13 @@
 			return;
 	}
 
-	printf("%s: mii_write timeout\n", device_xname(&sc->sc_dev));
+	printf("%s: mii_write timeout\n", device_xname(sc->sc_dev));
 }
 
 static void
-gem_mii_statchg(device_t dev)
+gem_mii_statchg(device_t self)
 {
-	struct gem_softc *sc = (void *)dev;
+	struct gem_softc *sc = device_private(self);
 #ifdef GEM_DEBUG
 	int instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
 #endif
@@ -2339,13 +2398,13 @@
 	bus_space_barrier(t, mac, GEM_MAC_TX_CONFIG, 4,
 	    BUS_SPACE_BARRIER_WRITE);
 	if (!gem_bitwait(sc, mac, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0))
-		aprint_normal_dev(&sc->sc_dev, "cannot disable TX MAC\n");
+		aprint_normal_dev(sc->sc_dev, "cannot disable TX MAC\n");
 	bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, txcfg);
 	bus_space_write_4(t, mac, GEM_MAC_RX_CONFIG, 0);
 	bus_space_barrier(t, mac, GEM_MAC_RX_CONFIG, 4,
 	    BUS_SPACE_BARRIER_WRITE);
 	if (!gem_bitwait(sc, mac, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0))
-		aprint_normal_dev(&sc->sc_dev, "cannot disable RX MAC\n");
+		aprint_normal_dev(sc->sc_dev, "cannot disable RX MAC\n");
 	bus_space_write_4(t, mac, GEM_MAC_RX_CONFIG, rxcfg);
 
 	v = bus_space_read_4(t, mac, GEM_MAC_CONTROL_CONFIG) &
@@ -2415,7 +2474,7 @@
 	if (s == IFM_AUTO) {
 		if (sc->sc_mii_media != s) {
 #ifdef GEM_DEBUG
-			aprint_debug_dev(&sc->sc_dev, "setting media to auto\n");
+			aprint_debug_dev(sc->sc_dev, "setting media to auto\n");
 #endif
 			sc->sc_mii_media = s;
 			if (ifp->if_flags & IFF_UP) {
@@ -2431,7 +2490,7 @@
 			if (sc->sc_mii_media != t) {
 				sc->sc_mii_media = t;
 #ifdef GEM_DEBUG
-				aprint_debug_dev(&sc->sc_dev,
+				aprint_debug_dev(sc->sc_dev,
 				    "setting media to 1000baseSX-%s\n",
 				    t == IFM_FDX ? "FDX" : "HDX");
 #endif
@@ -2502,14 +2561,57 @@
 	return (error);
 }
 
+static void
+gem_inten(struct gem_softc *sc)
+{
+	bus_space_tag_t t = sc->sc_bustag;
+	bus_space_handle_t h = sc->sc_h1;
+	uint32_t v;
 
-void
-gem_shutdown(void *arg)
+	if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0)
+		v = GEM_INTR_PCS;
+	else
+		v = GEM_INTR_MIF;
+	bus_space_write_4(t, h, GEM_INTMASK,
+		      ~(GEM_INTR_TX_INTME |
+			GEM_INTR_TX_EMPTY |
+			GEM_INTR_TX_MAC |
+			GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF|
+			GEM_INTR_RX_TAG_ERR | GEM_INTR_MAC_CONTROL|
+			GEM_INTR_BERR | v));
+}
+
+bool
+gem_resume(device_t self PMF_FN_ARGS)
+{
+	struct gem_softc *sc = device_private(self);
+
+	gem_inten(sc);
+
+	return true;
+}
+
+bool
+gem_suspend(device_t self PMF_FN_ARGS)
+{
+	struct gem_softc *sc = device_private(self);
+	bus_space_tag_t t = sc->sc_bustag;
+	bus_space_handle_t h = sc->sc_h1;
+
+	bus_space_write_4(t, h, GEM_INTMASK, ~(uint32_t)0);
+
+	return true;
+}
+
+bool
+gem_shutdown(device_t self, int howto)
 {
-	struct gem_softc *sc = (struct gem_softc *)arg;
+	struct gem_softc *sc = device_private(self);
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 
 	gem_stop(ifp, 1);
+
+	return true;
 }
 
 /*
@@ -2601,41 +2703,3 @@
 	sc->sc_if_flags = ifp->if_flags;
 	bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, v);
 }
-
-#if notyet
-
-/*
- * gem_power:
- *
- *	Power management (suspend/resume) hook.
- */
-void
-gem_power(int why, void *arg)
-{
-	struct gem_softc *sc = arg;
-	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	int s;
-
-	s = splnet();
-	switch (why) {
-	case PWR_SUSPEND:
-	case PWR_STANDBY:
-		gem_stop(ifp, 1);
-		if (sc->sc_power != NULL)
-			(*sc->sc_power)(sc, why);
-		break;
-	case PWR_RESUME:
-		if (ifp->if_flags & IFF_UP) {
-			if (sc->sc_power != NULL)
-				(*sc->sc_power)(sc, why);
-			gem_init(ifp);
-		}
-		break;
-	case PWR_SOFTSUSPEND:
-	case PWR_SOFTSTANDBY:
-	case PWR_SOFTRESUME:
-		break;
-	}
-	splx(s);
-}
-#endif

Index: src/sys/dev/ic/gemvar.h
diff -u src/sys/dev/ic/gemvar.h:1.18 src/sys/dev/ic/gemvar.h:1.19
--- src/sys/dev/ic/gemvar.h:1.18	Fri Feb  1 10:53:25 2008
+++ src/sys/dev/ic/gemvar.h	Mon Jul 27 18:10:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: gemvar.h,v 1.18 2008/02/01 10:53:25 jdc Exp $ */
+/*	$NetBSD: gemvar.h,v 1.19 2009/07/27 18:10:53 dyoung Exp $ */
 
 /*
  *
@@ -110,11 +110,27 @@
 	bus_dmamap_t rxs_dmamap;	/* our DMA map */
 };
 
+enum gem_attach_stage {
+	  GEM_ATT_BACKEND_2 = 0
+	, GEM_ATT_BACKEND_1
+	, GEM_ATT_FINISHED
+	, GEM_ATT_MII
+	, GEM_ATT_7
+	, GEM_ATT_6
+	, GEM_ATT_5
+	, GEM_ATT_4
+	, GEM_ATT_3
+	, GEM_ATT_2
+	, GEM_ATT_1
+	, GEM_ATT_0
+	, GEM_ATT_BACKEND_0
+};
+
 /*
  * Software state per device.
  */
 struct gem_softc {
-	struct device	sc_dev;		/* generic device information */
+	device_t	sc_dev;		/* generic device information */
 	struct ethercom sc_ethercom;	/* ethernet common data */
 	struct mii_data	sc_mii;		/* MII media control */
 	struct callout	sc_tick_ch;	/* tick callout */
@@ -125,6 +141,7 @@
 	bus_dmamap_t	sc_dmamap;	/* bus dma handle */
 	bus_space_handle_t sc_h1;	/* bus space handle for bank 1 regs */
 	bus_space_handle_t sc_h2;	/* bus space handle for bank 2 regs */
+	bus_size_t	sc_size;	/* bank 1 size */
 
 	int		sc_phys[2];	/* MII instance -> PHY map */
 
@@ -156,9 +173,6 @@
 #define	GEM_SERDES		0x0008	/* use the SERDES */
 #define	GEM_SERIAL		0x0010	/* use the serial link */
 
-	void *sc_sdhook;		/* shutdown hook */
-	void *sc_powerhook;		/* power management hook */
-
 	/*
 	 * Ring buffer DMA stuff.
 	 */
@@ -214,6 +228,8 @@
 	struct evcnt sc_ev_rxfull;
 	struct evcnt sc_ev_rxhist[9];
 #endif
+
+	enum gem_attach_stage	sc_att_stage;
 };
 
 #ifdef GEM_COUNTERS
@@ -291,8 +307,12 @@
 } while (0)
 
 #ifdef _KERNEL
+bool	gem_shutdown(device_t, int);
+bool	gem_suspend(device_t PMF_FN_PROTO);
+bool	gem_resume(device_t PMF_FN_PROTO);
 void	gem_attach(struct gem_softc *, const uint8_t *);
 int	gem_intr(void *);
+int	gem_detach(struct gem_softc *, int);
 
 void	gem_reset(struct gem_softc *);
 #endif /* _KERNEL */

Index: src/sys/dev/pci/if_gem_pci.c
diff -u src/sys/dev/pci/if_gem_pci.c:1.35 src/sys/dev/pci/if_gem_pci.c:1.36
--- src/sys/dev/pci/if_gem_pci.c:1.35	Tue May 12 08:23:00 2009
+++ src/sys/dev/pci/if_gem_pci.c	Mon Jul 27 18:10:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gem_pci.c,v 1.35 2009/05/12 08:23:00 cegger Exp $ */
+/*	$NetBSD: if_gem_pci.c,v 1.36 2009/07/27 18:10:53 dyoung Exp $ */
 
 /*
  *
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gem_pci.c,v 1.35 2009/05/12 08:23:00 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gem_pci.c,v 1.36 2009/07/27 18:10:53 dyoung Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -91,20 +91,28 @@
 struct gem_pci_softc {
 	struct	gem_softc	gsc_gem;	/* GEM device */
 	void			*gsc_ih;
+	pci_chipset_tag_t	gsc_pc;
+	pci_intr_handle_t	gsc_handle;
 };
 
-int	gem_match_pci(device_t, cfdata_t, void *);
-void	gem_attach_pci(device_t, device_t, void *);
-
-CFATTACH_DECL(gem_pci, sizeof(struct gem_pci_softc),
-    gem_match_pci, gem_attach_pci, NULL, NULL);
+static bool	gem_pci_estintr(struct gem_pci_softc *);
+static bool	gem_pci_suspend(device_t PMF_FN_PROTO);
+static bool	gem_pci_resume(device_t PMF_FN_PROTO);
+static int	gem_pci_detach(device_t, int);
+
+int	gem_pci_match(device_t, cfdata_t, void *);
+void	gem_pci_attach(device_t, device_t, void *);
+
+CFATTACH_DECL3_NEW(gem_pci, sizeof(struct gem_pci_softc),
+    gem_pci_match, gem_pci_attach, gem_pci_detach, NULL, NULL, NULL,
+    DVF_DETACH_SHUTDOWN);
 
 /*
  * Attach routines need to be split out to different bus-specific files.
  */
 
 int
-gem_match_pci(device_t parent, cfdata_t cf, void *aux)
+gem_pci_match(device_t parent, cfdata_t cf, void *aux)
 {
 	struct pci_attach_args *pa = aux;
 
@@ -157,13 +165,11 @@
 }
 
 void
-gem_attach_pci(device_t parent, device_t self, void *aux)
+gem_pci_attach(device_t parent, device_t self, void *aux)
 {
 	struct pci_attach_args *pa = aux;
 	struct gem_pci_softc *gsc = device_private(self);
 	struct gem_softc *sc = &gsc->gsc_gem;
-	pci_intr_handle_t ih;
-	const char *intrstr;
 	char devinfo[256];
 	uint8_t enaddr[ETHER_ADDR_LEN];
 #if GEM_USE_LOCAL_MAC_ADDRESS
@@ -192,6 +198,7 @@
 
 	aprint_naive(": Ethernet controller\n");
 
+	sc->sc_dev = self;
 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
 	sc->sc_chiprev = PCI_REVISION(pa->pa_class);
 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo, sc->sc_chiprev);
@@ -226,7 +233,7 @@
 	}
 
 	if (sc->sc_variant == GEM_UNKNOWN) {
-		aprint_error_dev(&sc->sc_dev, "unknown adaptor\n");
+		aprint_error_dev(sc->sc_dev, "unknown adaptor\n");
 		return;
 	}
 
@@ -235,14 +242,14 @@
 	/* XXX Need to check for a 64-bit mem BAR? */
 	if (pci_mapreg_map(pa, PCI_GEM_BASEADDR,
 	    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
-	    &sc->sc_bustag, &sc->sc_h1, NULL, NULL) != 0)
+	    &sc->sc_bustag, &sc->sc_h1, NULL, &sc->sc_size) != 0)
 	{
-		aprint_error_dev(&sc->sc_dev, "unable to map device registers\n");
+		aprint_error_dev(sc->sc_dev, "unable to map device registers\n");
 		return;
 	}
 	if (bus_space_subregion(sc->sc_bustag, sc->sc_h1,
 	    GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) {
-		aprint_error_dev(&sc->sc_dev, "unable to create bank 2 subregion\n");
+		aprint_error_dev(sc->sc_dev, "unable to create bank 2 subregion\n");
 		return;
 	}
 
@@ -285,7 +292,7 @@
 		}
 #ifdef GEM_DEBUG
 		/* PROM dump */
-		printf("%s: PROM dump (0x0000 to %04lx)\n", device_xname(&sc->sc_dev),
+		printf("%s: PROM dump (0x0000 to %04lx)\n", device_xname(sc->sc_dev),
 		    (sizeof buf) - 1);
 		i = 0;
 		j = 0;
@@ -368,7 +375,7 @@
 
 		node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
 		if (node == 0) {
-			aprint_error_dev(&sc->sc_dev, "unable to locate OpenFirmware node\n");
+			aprint_error_dev(sc->sc_dev, "unable to locate OpenFirmware node\n");
 			return;
 		}
 
@@ -378,25 +385,94 @@
 		OF_getprop(node, "local-mac-address", enaddr, sizeof(enaddr));
 	}
 #else
-		printf("%s: no Ethernet address found\n", device_xname(&sc->sc_dev));
+		printf("%s: no Ethernet address found\n", device_xname(sc->sc_dev));
 #endif /* macppc */
 #endif /* __sparc__ */
 
-	if (pci_intr_map(pa, &ih) != 0) {
-		aprint_error_dev(&sc->sc_dev, "unable to map interrupt\n");
+	if (pci_intr_map(pa, &gsc->gsc_handle) != 0) {
+		aprint_error_dev(sc->sc_dev, "unable to map interrupt\n");
 		return;
 	}
-	intrstr = pci_intr_string(pa->pa_pc, ih);
-	gsc->gsc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, gem_intr, sc);
+	gsc->gsc_pc = pa->pa_pc;
+	gem_pci_estintr(gsc);
+
+	/* Finish off the attach. */
+	gem_attach(sc, enaddr);
+
+	if (!pmf_device_register1(sc->sc_dev, gem_pci_suspend, gem_pci_resume,
+	                          gem_shutdown)) {
+		aprint_error_dev(sc->sc_dev,
+		    "could not establish power handlers\n");
+	} else
+		pmf_class_network_register(sc->sc_dev, &sc->sc_ethercom.ec_if);
+}
+
+static bool
+gem_pci_suspend(device_t self PMF_FN_ARGS)
+{
+	struct gem_pci_softc *gsc = device_private(self);
+
+	if (gsc->gsc_ih != NULL) {
+		pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih);
+		gsc->gsc_ih = NULL;
+	}
+
+	return true;
+}
+
+static bool
+gem_pci_estintr(struct gem_pci_softc *gsc)
+{
+	struct gem_softc *sc = &gsc->gsc_gem;
+	const char *intrstr;
+
+	intrstr = pci_intr_string(gsc->gsc_pc, gsc->gsc_handle);
+	gsc->gsc_ih = pci_intr_establish(gsc->gsc_pc, gsc->gsc_handle, IPL_NET,
+	    gem_intr, sc);
 	if (gsc->gsc_ih == NULL) {
-		aprint_error_dev(&sc->sc_dev, "unable to establish interrupt");
+		aprint_error_dev(sc->sc_dev, "unable to establish interrupt");
 		if (intrstr != NULL)
 			aprint_normal(" at %s", intrstr);
 		aprint_normal("\n");
-		return;
+		return false;
 	}
-	aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
+	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
+	return true;
+}
 
-	/* Finish off the attach. */
-	gem_attach(sc, enaddr);
+static bool
+gem_pci_resume(device_t self PMF_FN_ARGS)
+{
+	struct gem_pci_softc *gsc = device_private(self);
+
+	return gem_pci_estintr(gsc);
+}
+
+static int
+gem_pci_detach(device_t self, int flags)
+{
+	int rc;
+	struct gem_pci_softc *gsc = device_private(self);
+	struct gem_softc *sc = &gsc->gsc_gem;
+
+	switch (sc->sc_att_stage) {
+	case GEM_ATT_BACKEND_2:
+		pmf_device_deregister(self);
+		sc->sc_att_stage = GEM_ATT_FINISHED;
+		/*FALLTHROUGH*/
+	default:
+		if ((rc = gem_detach(sc, flags)) != 0)
+			return rc;
+		/*FALLTHROUGH*/
+	case GEM_ATT_BACKEND_1:
+		if (gsc->gsc_ih != NULL)
+			pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih);
+
+		bus_space_unmap(sc->sc_bustag, sc->sc_h1, sc->sc_size);
+		/*FALLTHROUGH*/
+	case GEM_ATT_BACKEND_0:
+		sc->sc_att_stage = GEM_ATT_BACKEND_0;
+		break;
+	}
+	return 0;
 }

Index: src/sys/dev/sbus/if_gem_sbus.c
diff -u src/sys/dev/sbus/if_gem_sbus.c:1.10 src/sys/dev/sbus/if_gem_sbus.c:1.11
--- src/sys/dev/sbus/if_gem_sbus.c:1.10	Tue May 12 14:43:59 2009
+++ src/sys/dev/sbus/if_gem_sbus.c	Mon Jul 27 18:10:54 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gem_sbus.c,v 1.10 2009/05/12 14:43:59 cegger Exp $	*/
+/*	$NetBSD: if_gem_sbus.c,v 1.11 2009/07/27 18:10:54 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gem_sbus.c,v 1.10 2009/05/12 14:43:59 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gem_sbus.c,v 1.11 2009/07/27 18:10:54 dyoung Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -85,10 +85,12 @@
 gemattach_sbus(device_t parent, device_t self, void *aux)
 {
 	struct sbus_attach_args *sa = aux;
-	struct gem_sbus_softc *gsc = (void *)self;
+	struct gem_sbus_softc *gsc = device_private(self);
 	struct gem_softc *sc = &gsc->gsc_gem;
 	uint8_t enaddr[ETHER_ADDR_LEN];
 
+	sc->sc_dev = self;
+
 	/* Pass on the bus tags */
 	sc->sc_bustag = sa->sa_bustag;
 	sc->sc_dmatag = sa->sa_dmatag;

Reply via email to