Author: yongari
Date: Thu Jan 14 22:04:32 2010
New Revision: 202313
URL: http://svn.freebsd.org/changeset/base/202313

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/7/sys/dev/ste/if_ste.c
  stable/7/sys/dev/ste/if_stereg.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/ste/if_ste.c
==============================================================================
--- stable/7/sys/dev/ste/if_ste.c       Thu Jan 14 22:04:08 2010        
(r202312)
+++ stable/7/sys/dev/ste/if_ste.c       Thu Jan 14 22:04:32 2010        
(r202313)
@@ -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 void    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)
@@ -598,6 +628,7 @@ ste_poll_locked(struct ifnet *ifp, enum 
 
        ste_rxeof(sc, count);
        ste_txeof(sc);
+       ste_txeoc(sc);
        if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
                ste_start_locked(ifp);
 
@@ -606,21 +637,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);
-               }
        }
 }
 #endif /* DEVICE_POLLING */
@@ -664,19 +685,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 */
@@ -771,41 +784,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;
@@ -848,43 +912,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.
@@ -931,7 +970,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);
@@ -940,18 +979,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,
@@ -963,7 +1007,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);
@@ -1069,7 +1113,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);
@@ -1080,7 +1124,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);
@@ -1498,6 +1543,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) {
@@ -1594,7 +1641,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
@@ -1603,28 +1650,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];
@@ -1674,6 +1737,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)
 {
@@ -1843,10 +1926,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);) {
@@ -1909,13 +1990,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/7/sys/dev/ste/if_stereg.h
==============================================================================
--- stable/7/sys/dev/ste/if_stereg.h    Thu Jan 14 22:04:08 2010        
(r202312)
+++ stable/7/sys/dev/ste/if_stereg.h    Thu Jan 14 22:04:32 2010        
(r202313)
@@ -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)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to