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;