From 6960d7d2cb2681b37c16366f3641e2b6a1ea5188 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 19 Aug 2012 15:56:21 +0800 Subject: [PATCH] jme: Don't immediately recycle the TX descriptor even if it is owned by us. This chip will always update the TX descriptor's 32bits fields in order, so even if the status field has been updated, i.e. OWN is cleared, it still does not mean that the buflen field has been updated. To avoid this race we don't immediately recycle the currently checking TX descriptor. Instead, next TX descriptor's OWN bit is checked, if it is cleared, then the updating of the currently checked TX descrptor is really done. This is intended to fix the seldom watchdog timeout that was observed on this chip. Thank devinchiu@jmicron.com very much for providing necessary information. --- sys/dev/netif/jme/if_jme.c | 31 +++++++++++++++++++++++++++---- sys/dev/netif/jme/if_jmevar.h | 1 + 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sys/dev/netif/jme/if_jme.c b/sys/dev/netif/jme/if_jme.c index dbe0600..9eee504 100644 --- a/sys/dev/netif/jme/if_jme.c +++ b/sys/dev/netif/jme/if_jme.c @@ -2003,9 +2003,7 @@ static void jme_txeof(struct jme_softc *sc) { struct ifnet *ifp = &sc->arpcom.ac_if; - struct jme_txdesc *txd; - uint32_t status; - int cons, nsegs; + int cons; cons = sc->jme_cdata.jme_tx_cons; if (cons == sc->jme_cdata.jme_tx_prod) @@ -2016,6 +2014,10 @@ jme_txeof(struct jme_softc *sc) * frames which have been transmitted. */ while (cons != sc->jme_cdata.jme_tx_prod) { + struct jme_txdesc *txd, *next_txd; + uint32_t status, next_status; + int next_cons, nsegs; + txd = &sc->jme_cdata.jme_txdesc[cons]; KASSERT(txd->tx_m != NULL, ("%s: freeing NULL mbuf!", __func__)); @@ -2024,6 +2026,27 @@ jme_txeof(struct jme_softc *sc) if ((status & JME_TD_OWN) == JME_TD_OWN) break; + /* + * NOTE: + * This chip will always update the TX descriptor's + * buflen field and this updating always happens + * after clearing the OWN bit, so even if the OWN + * bit is cleared by the chip, we still don't sure + * about whether the buflen field has been updated + * by the chip or not. To avoid this race, we wait + * for the next TX descriptor's OWN bit to be cleared + * by the chip before reusing this TX descriptor. + */ + next_cons = cons; + JME_DESC_ADD(next_cons, txd->tx_ndesc, + sc->jme_cdata.jme_tx_desc_cnt); + next_txd = &sc->jme_cdata.jme_txdesc[next_cons]; + if (next_txd->tx_m == NULL) + break; + next_status = le32toh(next_txd->tx_desc->flags); + if ((next_status & JME_TD_OWN) == JME_TD_OWN) + break; + if (status & (JME_TD_TMOUT | JME_TD_RETRY_EXP)) { ifp->if_oerrors++; } else { @@ -2058,7 +2081,7 @@ jme_txeof(struct jme_softc *sc) } sc->jme_cdata.jme_tx_cons = cons; - if (sc->jme_cdata.jme_tx_cnt == 0) + if (sc->jme_cdata.jme_tx_cnt < JME_MAXTXSEGS + 1) ifp->if_timer = 0; if (sc->jme_cdata.jme_tx_cnt + sc->jme_txd_spare <= diff --git a/sys/dev/netif/jme/if_jmevar.h b/sys/dev/netif/jme/if_jmevar.h index 893569c..5014fad 100644 --- a/sys/dev/netif/jme/if_jmevar.h +++ b/sys/dev/netif/jme/if_jmevar.h @@ -115,6 +115,7 @@ #define JME_RX_FIFO_SIZE 4000 #define JME_DESC_INC(x, y) ((x) = ((x) + 1) % (y)) +#define JME_DESC_ADD(x, d, y) ((x) = ((x) + (d)) % (y)) struct jme_txdesc { struct mbuf *tx_m; -- 1.7.7.2