From owner-svn-src-head@FreeBSD.ORG Tue Dec 22 23:57:11 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0FF041065692; Tue, 22 Dec 2009 23:57:11 +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 E82E78FC15; Tue, 22 Dec 2009 23:57:10 +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 nBMNvA6U080329; Tue, 22 Dec 2009 23:57:10 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nBMNvA4X080326; Tue, 22 Dec 2009 23:57:10 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <200912222357.nBMNvA4X080326@svn.freebsd.org> From: Pyun YongHyeon Date: Tue, 22 Dec 2009 23:57:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r200884 - head/sys/dev/ste X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Dec 2009 23:57:11 -0000 Author: yongari Date: Tue Dec 22 23:57:10 2009 New Revision: 200884 URL: http://svn.freebsd.org/changeset/base/200884 Log: 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: head/sys/dev/ste/if_ste.c head/sys/dev/ste/if_stereg.h Modified: head/sys/dev/ste/if_ste.c ============================================================================== --- head/sys/dev/ste/if_ste.c Tue Dec 22 22:45:03 2009 (r200883) +++ head/sys/dev/ste/if_ste.c Tue Dec 22 23:57:10 2009 (r200884) @@ -78,6 +78,9 @@ 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. */ @@ -118,6 +121,7 @@ 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 *); @@ -627,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); @@ -635,9 +640,6 @@ 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) ste_stats_update(sc); @@ -788,35 +790,63 @@ 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_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); } } @@ -1713,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) { @@ -1952,8 +2002,8 @@ ste_watchdog(struct ste_softc *sc) ifp->if_oerrors++; if_printf(ifp, "watchdog timeout\n"); - ste_txeoc(sc); ste_txeof(sc); + ste_txeoc(sc); ste_rxeof(sc, -1); ste_init_locked(sc); Modified: head/sys/dev/ste/if_stereg.h ============================================================================== --- head/sys/dev/ste/if_stereg.h Tue Dec 22 22:45:03 2009 (r200883) +++ head/sys/dev/ste/if_stereg.h Tue Dec 22 23:57:10 2009 (r200884) @@ -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