svn commit: r202311 - stable/8/sys/dev/ste

Pyun YongHyeon yongari at FreeBSD.org
Thu Jan 14 22:00:33 UTC 2010


Author: yongari
Date: Thu Jan 14 22:00:33 2010
New Revision: 202311
URL: http://svn.freebsd.org/changeset/base/202311

Log:
  MFC r200854,200856,200865,200873,200875,200877,200884
  
  r200854:
    Add minimal dealy while ste(4) is waiting for the end of active DMA
    cycle.
  
  r200856:
    Introduce sc_flags member variable and use it to keep track of
    link state and PHY related information.
    Remove ste_link and ste_one_phy variable of softc as it's not used
    anymore.
    While I'm here add IFF_DRV_RUNNING check in ste_start_locked().
  
  r200865:
    Reimplement miibus_statchg method. Don't rely on link state change
    interrupt. If we want to use link state change interrupt ste(4)
    should also implement auto-negotiation complete handler as well as
    various PHY access handling. Now link state change is handled by
    mii(4) polling so it will automatically update link state UP/DOWN
    events which in turn make ste(4) usable with lagg(4).
  
    r199559 added a private timer to drive watchdog and the timer also
    used to drive MAC statistics update. Because the MAC statistics
    update is called whenever statistics counter reaches near-full, it
    drove watchdog timer too fast such that it caused false watchdog
    timeouts under heavy TX traffic conditions.
    Fix the regression by separating ste_stats_update() from driving
    watchdog timer and introduce a new function ste_tick() that handles
    periodic job such as driving watchdog, MAC statistics update and
    link state check etc.
    While I'm here clear armed watchdog timer in ste_stop().
  
  r200873:
    Instead of relying on hard resetting of controller to stop
    receiving incoming traffics, try harder to gracefully stop active
    DMA cycles and then stop MACs. This is the way what datasheet
    recommends and seems to work reliably. Resetting controller while
    active DMAs are in progress is bad thing as we can't predict how
    DMAs touche allocated TX/RX buffers. This change ensures controller
    stop state before attempting to release allocated TX/RX buffers.
    Also update MAC statistics which could have been updated during the
    wait time of MAC stop.
  
    While I'm here remove unnecessary controller resets in various
    location. ste(4) no longer relies on hard controller reset to stop
    controller and resetting controller also clears all configured
    settings which makes it hard to implement WOL in near future.
    Now resetting a controller is performed in ste_init_locked().
  
  r200875:
    Prefer memory space register mapping over io space. If memory space
    mapping fails fall back to old io space mapping.
    While I'm here use PCIR_BAR macro.
  
  r200877:
    Prefer bus_write_{1,2,4}/bus_read_{1,2,4} to
    bus_space_write_{1,2,4}/bus_space_read_{1,2,4}.
    Remove unused ste_bhandle and ste_btag in softc.
  
  r200884:
    Reimplement Tx status error handler as recommended by datasheet.
    If ste(4) encounter TX underrun or excessive collisions the TX MAC
    of controller is stalled so driver should wake it up again. TX
    underrun requires increasing TX threshold value to minimize
    further TX underruns. Previously ste(4) used to reset controller
    to recover from TX underrun, excessive collision and reclaiming
    error. However datasheet says only TX underrun requires resetting
    entire controller. So implement ste_restart_tx() that restarts TX
    MAC and do not perform full reset except TX underrun case.
    Now ste(4) uses CSR_READ_2 instead of CSR_READ_1 to read
    STE_TX_STATUS register. This way ste(4) will also read frame id
    value and we can write the same value back to STE_TX_FRAMEID
    register instead of overwriting it to 0. The datasheet was wrong
    in write back of STE_TX_STATUS so add some comments why we do so.
    Also always invoke ste_txeoc() after ste_txeof() in ste_poll as
    without reading TX status register can stall TX MAC.

Modified:
  stable/8/sys/dev/ste/if_ste.c
  stable/8/sys/dev/ste/if_stereg.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/ste/if_ste.c
==============================================================================
--- stable/8/sys/dev/ste/if_ste.c	Thu Jan 14 21:54:20 2010	(r202310)
+++ stable/8/sys/dev/ste/if_ste.c	Thu Jan 14 22:00:33 2010	(r202311)
@@ -74,12 +74,13 @@ __FBSDID("$FreeBSD$");
 /* "device miibus" required.  See GENERIC if you get errors here. */
 #include "miibus_if.h"
 
-#define STE_USEIOSPACE
-
 MODULE_DEPEND(ste, pci, 1, 1, 1);
 MODULE_DEPEND(ste, ether, 1, 1, 1);
 MODULE_DEPEND(ste, miibus, 1, 1, 1);
 
+/* Define to show Tx error status. */
+#define	STE_SHOW_TXERRORS
+
 /*
  * Various supported device vendors/types and their names.
  */
@@ -120,25 +121,19 @@ static int	ste_miibus_writereg(device_t,
 static int	ste_newbuf(struct ste_softc *, struct ste_chain_onefrag *);
 static int	ste_read_eeprom(struct ste_softc *, caddr_t, int, int, int);
 static void	ste_reset(struct ste_softc *);
+static void	ste_restart_tx(struct ste_softc *);
 static int	ste_rxeof(struct ste_softc *, int);
 static void	ste_setmulti(struct ste_softc *);
 static void	ste_start(struct ifnet *);
 static void	ste_start_locked(struct ifnet *);
-static void	ste_stats_update(void *);
+static void	ste_stats_update(struct ste_softc *);
 static void	ste_stop(struct ste_softc *);
+static void	ste_tick(void *);
 static void	ste_txeoc(struct ste_softc *);
 static void	ste_txeof(struct ste_softc *);
 static void	ste_wait(struct ste_softc *);
 static void	ste_watchdog(struct ste_softc *);
 
-#ifdef STE_USEIOSPACE
-#define STE_RES			SYS_RES_IOPORT
-#define STE_RID			STE_PCI_LOIO
-#else
-#define STE_RES			SYS_RES_MEMORY
-#define STE_RID			STE_PCI_LOMEM
-#endif
-
 static device_method_t ste_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		ste_probe),
@@ -369,7 +364,7 @@ ste_miibus_readreg(device_t dev, int phy
 
 	sc = device_get_softc(dev);
 
-	if ( sc->ste_one_phy && phy != 0 )
+	if ((sc->ste_flags & STE_FLAG_ONE_PHY) != 0 && phy != 0)
 		return (0);
 
 	bzero((char *)&frame, sizeof(frame));
@@ -404,15 +399,49 @@ ste_miibus_statchg(device_t dev)
 {
 	struct ste_softc *sc;
 	struct mii_data *mii;
+	struct ifnet *ifp;
+	uint16_t cfg;
 
 	sc = device_get_softc(dev);
 
 	mii = device_get_softc(sc->ste_miibus);
+	ifp = sc->ste_ifp;
+	if (mii == NULL || ifp == NULL ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
 
-	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
-		STE_SETBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
-	} else {
-		STE_CLRBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
+	sc->ste_flags &= ~STE_FLAG_LINK;
+	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+	    (IFM_ACTIVE | IFM_AVALID)) {
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_10_T:
+		case IFM_100_TX:
+		case IFM_100_FX:
+		case IFM_100_T4:
+			sc->ste_flags |= STE_FLAG_LINK;
+		default:
+			break;
+		}
+	}
+
+	/* Program MACs with resolved speed/duplex/flow-control. */
+	if ((sc->ste_flags & STE_FLAG_LINK) != 0) {
+		cfg = CSR_READ_2(sc, STE_MACCTL0);
+		cfg &= ~(STE_MACCTL0_FLOWCTL_ENABLE | STE_MACCTL0_FULLDUPLEX);
+		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+			/*
+			 * ST201 data sheet says driver should enable receiving
+			 * MAC control frames bit of receive mode register to
+			 * receive flow-control frames but the register has no
+			 * such bits. In addition the controller has no ability
+			 * to send pause frames so it should be handled in
+			 * driver. Implementing pause timer handling in driver
+			 * layer is not trivial, so don't enable flow-control
+			 * here.
+			 */
+			cfg |= STE_MACCTL0_FULLDUPLEX;
+		}
+		CSR_WRITE_2(sc, STE_MACCTL0, cfg);
 	}
 }
 
@@ -438,7 +467,7 @@ ste_ifmedia_upd_locked(struct ifnet *ifp
 	sc = ifp->if_softc;
 	STE_LOCK_ASSERT(sc);
 	mii = device_get_softc(sc->ste_miibus);
-	sc->ste_link = 0;
+	sc->ste_flags &= ~STE_FLAG_LINK;
 	if (mii->mii_instance) {
 		struct mii_softc	*miisc;
 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
@@ -471,6 +500,7 @@ ste_wait(struct ste_softc *sc)
 	for (i = 0; i < STE_TIMEOUT; i++) {
 		if (!(CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_DMA_HALTINPROG))
 			break;
+		DELAY(1);
 	}
 
 	if (i == STE_TIMEOUT)
@@ -601,6 +631,7 @@ ste_poll_locked(struct ifnet *ifp, enum 
 
 	rx_npkts = ste_rxeof(sc, count);
 	ste_txeof(sc);
+	ste_txeoc(sc);
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		ste_start_locked(ifp);
 
@@ -609,21 +640,11 @@ ste_poll_locked(struct ifnet *ifp, enum 
 
 		status = CSR_READ_2(sc, STE_ISR_ACK);
 
-		if (status & STE_ISR_TX_DONE)
-			ste_txeoc(sc);
-
-		if (status & STE_ISR_STATS_OFLOW) {
-			callout_stop(&sc->ste_stat_callout);
+		if (status & STE_ISR_STATS_OFLOW)
 			ste_stats_update(sc);
-		}
-
-		if (status & STE_ISR_LINKEVENT)
-			mii_pollstat(device_get_softc(sc->ste_miibus));
 
-		if (status & STE_ISR_HOSTERR) {
-			ste_reset(sc);
+		if (status & STE_ISR_HOSTERR)
 			ste_init_locked(sc);
-		}
 	}
 	return (rx_npkts);
 }
@@ -668,19 +689,11 @@ ste_intr(void *xsc)
 		if (status & STE_ISR_TX_DONE)
 			ste_txeoc(sc);
 
-		if (status & STE_ISR_STATS_OFLOW) {
-			callout_stop(&sc->ste_stat_callout);
+		if (status & STE_ISR_STATS_OFLOW)
 			ste_stats_update(sc);
-		}
-
-		if (status & STE_ISR_LINKEVENT)
-			mii_pollstat(device_get_softc(sc->ste_miibus));
 
-
-		if (status & STE_ISR_HOSTERR) {
-			ste_reset(sc);
+		if (status & STE_ISR_HOSTERR)
 			ste_init_locked(sc);
-		}
 	}
 
 	/* Re-enable interrupts */
@@ -777,41 +790,92 @@ ste_rxeof(struct ste_softc *sc, int coun
 static void
 ste_txeoc(struct ste_softc *sc)
 {
+	uint16_t txstat;
 	struct ifnet *ifp;
-	uint8_t txstat;
+
+	STE_LOCK_ASSERT(sc);
 
 	ifp = sc->ste_ifp;
 
-	while ((txstat = CSR_READ_1(sc, STE_TX_STATUS)) &
-	    STE_TXSTATUS_TXDONE) {
-		if (txstat & STE_TXSTATUS_UNDERRUN ||
-		    txstat & STE_TXSTATUS_EXCESSCOLLS ||
-		    txstat & STE_TXSTATUS_RECLAIMERR) {
+	/*
+	 * STE_TX_STATUS register implements a queue of up to 31
+	 * transmit status byte. Writing an arbitrary value to the
+	 * register will advance the queue to the next transmit
+	 * status byte. This means if driver does not read
+	 * STE_TX_STATUS register after completing sending more
+	 * than 31 frames the controller would be stalled so driver
+	 * should re-wake the Tx MAC. This is the most severe
+	 * limitation of ST201 based controller.
+	 */
+	for (;;) {
+		txstat = CSR_READ_2(sc, STE_TX_STATUS);
+		if ((txstat & STE_TXSTATUS_TXDONE) == 0)
+			break;
+		if ((txstat & (STE_TXSTATUS_UNDERRUN |
+		    STE_TXSTATUS_EXCESSCOLLS | STE_TXSTATUS_RECLAIMERR |
+		    STE_TXSTATUS_STATSOFLOW)) != 0) {
 			ifp->if_oerrors++;
-			device_printf(sc->ste_dev,
-			    "transmission error: %x\n", txstat);
-
-			ste_reset(sc);
-			ste_init_locked(sc);
-
-			if (txstat & STE_TXSTATUS_UNDERRUN &&
+#ifdef	STE_SHOW_TXERRORS
+			device_printf(sc->ste_dev, "TX error : 0x%b\n",
+			    txstat & 0xFF, STE_ERR_BITS);
+#endif
+			if ((txstat & STE_TXSTATUS_UNDERRUN) != 0 &&
 			    sc->ste_tx_thresh < STE_PACKET_SIZE) {
 				sc->ste_tx_thresh += STE_MIN_FRAMELEN;
+				if (sc->ste_tx_thresh > STE_PACKET_SIZE)
+					sc->ste_tx_thresh = STE_PACKET_SIZE;
 				device_printf(sc->ste_dev,
-				    "tx underrun, increasing tx"
+				    "TX underrun, increasing TX"
 				    " start threshold to %d bytes\n",
 				    sc->ste_tx_thresh);
+				/* Make sure to disable active DMA cycles. */
+				STE_SETBIT4(sc, STE_DMACTL,
+				    STE_DMACTL_TXDMA_STALL);
+				ste_wait(sc);
+				ste_init_locked(sc);
+				break;
 			}
-			CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
-			CSR_WRITE_2(sc, STE_TX_RECLAIM_THRESH,
-			    (STE_PACKET_SIZE >> 4));
+			/* Restart Tx. */
+			ste_restart_tx(sc);
 		}
-		ste_init_locked(sc);
+		/*
+		 * Advance to next status and ACK TxComplete
+		 * interrupt. ST201 data sheet was wrong here, to
+		 * get next Tx status, we have to write both
+		 * STE_TX_STATUS and STE_TX_FRAMEID register.
+		 * Otherwise controller returns the same status
+		 * as well as not acknowledge Tx completion
+		 * interrupt.
+		 */
 		CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
 	}
 }
 
 static void
+ste_tick(void *arg)
+{
+	struct ste_softc *sc;
+	struct mii_data *mii;
+
+	sc = (struct ste_softc *)arg;
+
+	STE_LOCK_ASSERT(sc);
+
+	mii = device_get_softc(sc->ste_miibus);
+	mii_tick(mii);
+	/*
+	 * ukphy(4) does not seem to generate CB that reports
+	 * resolved link state so if we know we lost a link,
+	 * explicitly check the link state.
+	 */
+	if ((sc->ste_flags & STE_FLAG_LINK) == 0)
+		ste_miibus_statchg(sc->ste_dev);
+	ste_stats_update(sc);
+	ste_watchdog(sc);
+	callout_reset(&sc->ste_callout, hz, ste_tick, sc);
+}
+
+static void
 ste_txeof(struct ste_softc *sc)
 {
 	struct ifnet *ifp;
@@ -854,43 +918,18 @@ ste_txeof(struct ste_softc *sc)
 }
 
 static void
-ste_stats_update(void *xsc)
+ste_stats_update(struct ste_softc *sc)
 {
-	struct ste_softc *sc;
 	struct ifnet *ifp;
-	struct mii_data *mii;
 
-	sc = xsc;
 	STE_LOCK_ASSERT(sc);
 
 	ifp = sc->ste_ifp;
-	mii = device_get_softc(sc->ste_miibus);
-
 	ifp->if_collisions += CSR_READ_1(sc, STE_LATE_COLLS)
 	    + CSR_READ_1(sc, STE_MULTI_COLLS)
 	    + CSR_READ_1(sc, STE_SINGLE_COLLS);
-
-	if (!sc->ste_link) {
-		mii_pollstat(mii);
-		if (mii->mii_media_status & IFM_ACTIVE &&
-		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
-			sc->ste_link++;
-			/*
-			* we don't get a call-back on re-init so do it
-			* otherwise we get stuck in the wrong link state
-			*/
-			ste_miibus_statchg(sc->ste_dev);
-			if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-				ste_start_locked(ifp);
-		}
-	}
-
-	if (sc->ste_timer > 0 && --sc->ste_timer == 0)
-		ste_watchdog(sc);
-	callout_reset(&sc->ste_stat_callout, hz, ste_stats_update, sc);
 }
 
-
 /*
  * Probe for a Sundance ST201 chip. Check the PCI vendor and device
  * IDs against our list and return a device name if we find a match.
@@ -937,7 +976,7 @@ ste_attach(device_t dev)
 	if (pci_get_vendor(dev) == DL_VENDORID &&
 	    pci_get_device(dev) == DL_DEVICEID_DL10050 &&
 	    pci_get_revid(dev) == 0x12 )
-		sc->ste_one_phy = 1;
+		sc->ste_flags |= STE_FLAG_ONE_PHY;
 
 	mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
@@ -946,18 +985,23 @@ ste_attach(device_t dev)
 	 */
 	pci_enable_busmaster(dev);
 
-	rid = STE_RID;
-	sc->ste_res = bus_alloc_resource_any(dev, STE_RES, &rid, RF_ACTIVE);
-
+	/* Prefer memory space register mapping over IO space. */
+	sc->ste_res_id = PCIR_BAR(1);
+	sc->ste_res_type = SYS_RES_MEMORY;
+	sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type,
+	    &sc->ste_res_id, RF_ACTIVE);
+	if (sc->ste_res == NULL) {
+		sc->ste_res_id = PCIR_BAR(0);
+		sc->ste_res_type = SYS_RES_IOPORT;
+		sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type,
+		    &sc->ste_res_id, RF_ACTIVE);
+	}
 	if (sc->ste_res == NULL) {
 		device_printf(dev, "couldn't map ports/memory\n");
 		error = ENXIO;
 		goto fail;
 	}
 
-	sc->ste_btag = rman_get_bustag(sc->ste_res);
-	sc->ste_bhandle = rman_get_bushandle(sc->ste_res);
-
 	/* Allocate interrupt */
 	rid = 0;
 	sc->ste_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -969,7 +1013,7 @@ ste_attach(device_t dev)
 		goto fail;
 	}
 
-	callout_init_mtx(&sc->ste_stat_callout, &sc->ste_mtx, 0);
+	callout_init_mtx(&sc->ste_callout, &sc->ste_mtx, 0);
 
 	/* Reset the adapter. */
 	ste_reset(sc);
@@ -1075,7 +1119,7 @@ ste_detach(device_t dev)
 		STE_LOCK(sc);
 		ste_stop(sc);
 		STE_UNLOCK(sc);
-		callout_drain(&sc->ste_stat_callout);
+		callout_drain(&sc->ste_callout);
 	}
 	if (sc->ste_miibus)
 		device_delete_child(dev, sc->ste_miibus);
@@ -1086,7 +1130,8 @@ ste_detach(device_t dev)
 	if (sc->ste_irq)
 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
 	if (sc->ste_res)
-		bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res);
+		bus_release_resource(dev, sc->ste_res_type, sc->ste_res_id,
+		    sc->ste_res);
 
 	if (ifp)
 		if_free(ifp);
@@ -1504,6 +1549,8 @@ ste_init_locked(struct ste_softc *sc)
 	ifp = sc->ste_ifp;
 
 	ste_stop(sc);
+	/* Reset the chip to a known state. */
+	ste_reset(sc);
 
 	/* Init our MAC address */
 	for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
@@ -1600,7 +1647,7 @@ ste_init_locked(struct ste_softc *sc)
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
-	callout_reset(&sc->ste_stat_callout, hz, ste_stats_update, sc);
+	callout_reset(&sc->ste_callout, hz, ste_tick, sc);
 }
 
 static void
@@ -1609,28 +1656,44 @@ ste_stop(struct ste_softc *sc)
 	struct ifnet *ifp;
 	struct ste_chain_onefrag *cur_rx;
 	struct ste_chain *cur_tx;
+	uint32_t val;
 	int i;
 
 	STE_LOCK_ASSERT(sc);
 	ifp = sc->ste_ifp;
 
-	callout_stop(&sc->ste_stat_callout);
+	callout_stop(&sc->ste_callout);
+	sc->ste_timer = 0;
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
 
 	CSR_WRITE_2(sc, STE_IMR, 0);
-	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_DISABLE);
-	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_DISABLE);
-	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_DISABLE);
-	STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
-	STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
+	/* Stop pending DMA. */
+	val = CSR_READ_4(sc, STE_DMACTL);
+	val |= STE_DMACTL_TXDMA_STALL | STE_DMACTL_RXDMA_STALL;
+	CSR_WRITE_4(sc, STE_DMACTL, val);
 	ste_wait(sc);
-	/*
-	 * Try really hard to stop the RX engine or under heavy RX
-	 * data chip will write into de-allocated memory.
-	 */
-	ste_reset(sc);
-
-	sc->ste_link = 0;
+	/* Disable auto-polling. */
+	CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 0);
+	CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0);
+	/* Nullify DMA address to stop any further DMA. */
+	CSR_WRITE_4(sc, STE_RX_DMALIST_PTR, 0);
+	CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0);
+	/* Stop TX/RX MAC. */
+	val = CSR_READ_2(sc, STE_MACCTL1);
+	val |= STE_MACCTL1_TX_DISABLE | STE_MACCTL1_RX_DISABLE |
+	    STE_MACCTL1_STATS_DISABLE;
+	CSR_WRITE_2(sc, STE_MACCTL1, val);
+	for (i = 0; i < STE_TIMEOUT; i++) {
+		DELAY(10);
+		if ((CSR_READ_2(sc, STE_MACCTL1) & (STE_MACCTL1_TX_DISABLE |
+		    STE_MACCTL1_RX_DISABLE | STE_MACCTL1_STATS_DISABLE)) == 0)
+			break;
+	}
+	if (i == STE_TIMEOUT)
+		device_printf(sc->ste_dev, "Stopping MAC timed out\n");
+	/* Acknowledge any pending interrupts. */
+	CSR_READ_2(sc, STE_ISR_ACK);
+	ste_stats_update(sc);
 
 	for (i = 0; i < STE_RX_LIST_CNT; i++) {
 		cur_rx = &sc->ste_cdata.ste_rx_chain[i];
@@ -1680,6 +1743,26 @@ ste_reset(struct ste_softc *sc)
 		device_printf(sc->ste_dev, "global reset never completed\n");
 }
 
+static void
+ste_restart_tx(struct ste_softc *sc)
+{
+	uint16_t mac;
+	int i;
+
+	for (i = 0; i < STE_TIMEOUT; i++) {
+		mac = CSR_READ_2(sc, STE_MACCTL1);
+		mac |= STE_MACCTL1_TX_ENABLE;
+		CSR_WRITE_2(sc, STE_MACCTL1, mac);
+		mac = CSR_READ_2(sc, STE_MACCTL1);
+		if ((mac & STE_MACCTL1_TX_ENABLED) != 0)
+			break;
+		DELAY(10);
+	}
+
+	if (i == STE_TIMEOUT)
+		device_printf(sc->ste_dev, "starting Tx failed");
+}
+
 static int
 ste_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
@@ -1849,10 +1932,8 @@ ste_start_locked(struct ifnet *ifp)
 	sc = ifp->if_softc;
 	STE_LOCK_ASSERT(sc);
 
-	if (!sc->ste_link)
-		return;
-
-	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
+	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING || (sc->ste_flags & STE_FLAG_LINK) == 0)
 		return;
 
 	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
@@ -1915,13 +1996,15 @@ ste_watchdog(struct ste_softc *sc)
 	ifp = sc->ste_ifp;
 	STE_LOCK_ASSERT(sc);
 
+	if (sc->ste_timer == 0 || --sc->ste_timer)
+		return;
+
 	ifp->if_oerrors++;
 	if_printf(ifp, "watchdog timeout\n");
 
-	ste_txeoc(sc);
 	ste_txeof(sc);
+	ste_txeoc(sc);
 	ste_rxeof(sc, -1);
-	ste_reset(sc);
 	ste_init_locked(sc);
 
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))

Modified: stable/8/sys/dev/ste/if_stereg.h
==============================================================================
--- stable/8/sys/dev/ste/if_stereg.h	Thu Jan 14 21:54:20 2010	(r202310)
+++ stable/8/sys/dev/ste/if_stereg.h	Thu Jan 14 22:00:33 2010	(r202311)
@@ -253,6 +253,11 @@
 #define STE_TXSTATUS_TXINTR_REQ		0x40
 #define STE_TXSTATUS_TXDONE		0x80
 
+#define	STE_ERR_BITS			"\20"				\
+					"\2RECLAIM\3STSOFLOW"		\
+					"\4EXCESSCOLLS\5UNDERRUN"	\
+					"\6INTREQ\7DONE"
+
 #define STE_ISRACK_INTLATCH		0x0001
 #define STE_ISRACK_HOSTERR		0x0002
 #define STE_ISRACK_TX_DONE		0x0004
@@ -276,10 +281,9 @@
 #define STE_IMR_TX_DMADONE		0x0200
 #define STE_IMR_RX_DMADONE		0x0400
 
-#define STE_INTRS					\
+#define STE_INTRS				\
 	(STE_IMR_RX_DMADONE|STE_IMR_TX_DMADONE|	\
-	STE_IMR_TX_DONE|STE_IMR_HOSTERR| \
-        STE_IMR_LINKEVENT)
+	STE_IMR_TX_DONE|STE_IMR_HOSTERR)
 
 #define STE_ISR_INTLATCH		0x0001
 #define STE_ISR_HOSTERR			0x0002
@@ -466,18 +470,18 @@ struct ste_desc_onefrag {
  * register space access macros
  */
 #define CSR_WRITE_4(sc, reg, val)	\
-	bus_space_write_4(sc->ste_btag, sc->ste_bhandle, reg, val)
+	bus_write_4((sc)->ste_res, reg, val)
 #define CSR_WRITE_2(sc, reg, val)	\
-	bus_space_write_2(sc->ste_btag, sc->ste_bhandle, reg, val)
+	bus_write_2((sc)->ste_res, reg, val)
 #define CSR_WRITE_1(sc, reg, val)	\
-	bus_space_write_1(sc->ste_btag, sc->ste_bhandle, reg, val)
+	bus_write_1((sc)->ste_res, reg, val)
 
 #define CSR_READ_4(sc, reg)		\
-	bus_space_read_4(sc->ste_btag, sc->ste_bhandle, reg)
+	bus_read_4((sc)->ste_res, reg)
 #define CSR_READ_2(sc, reg)		\
-	bus_space_read_2(sc->ste_btag, sc->ste_bhandle, reg)
+	bus_read_2((sc)->ste_res, reg)
 #define CSR_READ_1(sc, reg)		\
-	bus_space_read_1(sc->ste_btag, sc->ste_bhandle, reg)
+	bus_read_1((sc)->ste_res, reg)
 
 #define	STE_DESC_ALIGN		8
 #define STE_RX_LIST_CNT		128
@@ -545,23 +549,24 @@ struct ste_chain_data {
 
 struct ste_softc {
 	struct ifnet		*ste_ifp;
-	bus_space_tag_t		ste_btag;
-	bus_space_handle_t	ste_bhandle;
 	struct resource		*ste_res;
+	int			ste_res_id;
+	int			ste_res_type;
 	struct resource		*ste_irq;
 	void			*ste_intrhand;
 	struct ste_type		*ste_info;
 	device_t		ste_miibus;
 	device_t		ste_dev;
 	int			ste_tx_thresh;
-	uint8_t			ste_link;
+	int			ste_flags;
+#define	STE_FLAG_ONE_PHY	0x0001
+#define	STE_FLAG_LINK		0x8000
 	int			ste_if_flags;
 	int			ste_timer;
 	struct ste_list_data	ste_ldata;
 	struct ste_chain_data	ste_cdata;
-	struct callout		ste_stat_callout;
+	struct callout		ste_callout;
 	struct mtx		ste_mtx;
-	uint8_t			ste_one_phy;
 };
 
 #define	STE_LOCK(_sc)		mtx_lock(&(_sc)->ste_mtx)


More information about the svn-src-stable-8 mailing list