diff options
author | wpaul <wpaul@FreeBSD.org> | 1999-06-19 00:36:56 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1999-06-19 00:36:56 +0000 |
commit | 2f586076cdac59250332cc3e33017bc718a6c8b4 (patch) | |
tree | 5aaf2350b53ef087e74cf0a79590df646128f2dc /sys/pci/if_ti.c | |
parent | 517a8eacaf9de8fce05ee46d0bb7f0f1d4c692b9 (diff) | |
download | FreeBSD-src-2f586076cdac59250332cc3e33017bc718a6c8b4.zip FreeBSD-src-2f586076cdac59250332cc3e33017bc718a6c8b4.tar.gz |
Add a transmit descriptor usage counter and use it to absolutely,
positively not let ti_encap() fill up the TX ring all the way and wrap
around. This fixes a potential transmit lockup where a really fast
machine (or particular TX traffic pattern) can overrun the end of the
ring.
Reported by: John Plevyak <jplevyak@inktomi.com>
Diffstat (limited to 'sys/pci/if_ti.c')
-rw-r--r-- | sys/pci/if_ti.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/sys/pci/if_ti.c b/sys/pci/if_ti.c index 96370ed..a4af011 100644 --- a/sys/pci/if_ti.c +++ b/sys/pci/if_ti.c @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_ti.c,v 1.5 1999/05/09 17:07:00 peter Exp $ + * $Id: if_ti.c,v 1.6 1999/05/24 14:56:55 wpaul Exp $ */ /* @@ -128,7 +128,7 @@ #if !defined(lint) static const char rcsid[] = - "$Id: if_ti.c,v 1.5 1999/05/09 17:07:00 peter Exp $"; + "$Id: if_ti.c,v 1.6 1999/05/24 14:56:55 wpaul Exp $"; #endif /* @@ -1065,6 +1065,7 @@ static void ti_free_tx_ring(sc) static int ti_init_tx_ring(sc) struct ti_softc *sc; { + sc->ti_txcnt = 0; sc->ti_tx_saved_considx = 0; CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, 0); return(0); @@ -1920,6 +1921,7 @@ static void ti_txeof(sc) m_freem(sc->ti_cdata.ti_tx_chain[idx]); sc->ti_cdata.ti_tx_chain[idx] = NULL; } + sc->ti_txcnt--; TI_INC(sc->ti_tx_saved_considx, TI_TX_RING_CNT); ifp->if_timer = 0; } @@ -1996,7 +1998,7 @@ static int ti_encap(sc, m_head, txidx) { struct ti_tx_desc *f = NULL; struct mbuf *m; - u_int32_t frag, cur; + u_int32_t frag, cur, cnt = 0; #if NVLAN > 0 struct ifvlan *ifv = NULL; @@ -2045,8 +2047,15 @@ static int ti_encap(sc, m_head, txidx) f->ti_vlan_tag = 0; } #endif + /* + * Sanity check: avoid coming within 16 descriptors + * of the end of the ring. + */ + if ((TI_TX_RING_CNT - (sc->ti_txcnt + cnt)) < 16) + return(ENOBUFS); cur = frag; TI_INC(frag, TI_TX_RING_CNT); + cnt++; } } @@ -2062,6 +2071,7 @@ static int ti_encap(sc, m_head, txidx) else sc->ti_rdata->ti_tx_ring[cur].ti_flags |= TI_BDFLAG_END; sc->ti_cdata.ti_tx_chain[cur] = m_head; + sc->ti_txcnt += cnt; *txidx = frag; |