From owner-svn-src-stable-8@FreeBSD.ORG Thu Jan 14 22:00:33 2010 Return-Path: Delivered-To: svn-src-stable-8@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 64C8E106568F; Thu, 14 Jan 2010 22:00:33 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 531E98FC1E; Thu, 14 Jan 2010 22:00:33 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o0EM0Xe3058500; Thu, 14 Jan 2010 22:00:33 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0EM0Xe1058497; Thu, 14 Jan 2010 22:00:33 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201001142200.o0EM0Xe1058497@svn.freebsd.org> From: Pyun YongHyeon Date: Thu, 14 Jan 2010 22:00:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r202311 - stable/8/sys/dev/ste X-BeenThere: svn-src-stable-8@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 8-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jan 2010 22:00:33 -0000 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)