summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2004-06-01 02:43:29 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2004-06-01 02:43:29 +0000
commitae39653843383f17ec01a4ba5af4ca05a7819846 (patch)
tree93e34d53d2180e83875e3930657b89d7ce541855 /sys
parentfbfad507aaefb936f0ef2a03ce2bdf8b0decc28f (diff)
some revisions have issues sending lots of packets.
apply a workaround from freebsd. pr3061 from nick nauwelaerts
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_sf.c68
-rw-r--r--sys/dev/pci/if_sfreg.h5
2 files changed, 62 insertions, 11 deletions
diff --git a/sys/dev/pci/if_sf.c b/sys/dev/pci/if_sf.c
index 69a70edb8e7..797de5e42d6 100644
--- a/sys/dev/pci/if_sf.c
+++ b/sys/dev/pci/if_sf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sf.c,v 1.24 2004/05/30 02:01:31 mcbride Exp $ */
+/* $OpenBSD: if_sf.c,v 1.25 2004/06/01 02:43:28 tedu Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
@@ -160,6 +160,7 @@ void sf_miibus_statchg(struct device *);
u_int32_t csr_read_4(struct sf_softc *, int);
void csr_write_4(struct sf_softc *, int, u_int32_t);
+void sf_txthresh_adjust(struct sf_softc *);
#define SF_SETBIT(sc, reg, x) \
csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
@@ -928,18 +929,22 @@ void sf_txeof(sc)
while (cmpconsidx != cmpprodidx) {
cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
- SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
ifp->if_opackets++;
- else
+ else {
+ if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
+ sf_txthresh_adjust(sc);
ifp->if_oerrors++;
+ }
sc->sf_tx_cnt--;
if (cur_tx->sf_mbuf != NULL) {
m_freem(cur_tx->sf_mbuf);
cur_tx->sf_mbuf = NULL;
- }
+ } else
+ break;
+ SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
}
ifp->if_timer = 0;
@@ -952,6 +957,29 @@ void sf_txeof(sc)
return;
}
+void
+sf_txthresh_adjust(sc)
+ struct sf_softc *sc;
+{
+ u_int32_t txfctl;
+ u_int8_t txthresh;
+
+ txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
+ txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
+ if (txthresh < 0xFF) {
+ txthresh++;
+ txfctl &= ~SF_TXFRMCTL_TXTHRESH;
+ txfctl |= txthresh;
+#ifdef DIAGNOSTIC
+ printf("%s: tx underrun, increasing tx threshold to %d bytes\n",
+ sc->sc_dev.dv_xname, txthresh * 4);
+#endif
+ csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
+ }
+
+ return;
+}
+
int sf_intr(arg)
void *arg;
{
@@ -982,9 +1010,15 @@ int sf_intr(arg)
if (status & SF_ISR_RXDQ1_DMADONE)
sf_rxeof(sc);
- if (status & SF_ISR_TX_TXDONE)
+ if (status & SF_ISR_TX_TXDONE ||
+ status & SF_ISR_TX_DMADONE ||
+ status & SF_ISR_TX_QUEUEDONE ||
+ status & SF_ISR_TX_LOFIFO)
sf_txeof(sc);
+ if (status & SF_ISR_TX_LOFIFO)
+ sf_txthresh_adjust(sc);
+
if (status & SF_ISR_ABNORMALINTR) {
if (status & SF_ISR_STATSOFLOW) {
timeout_del(&sc->sc_stats_tmo);
@@ -1145,7 +1179,8 @@ int sf_encap(sc, c, m_head)
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
if (m_new == NULL) {
- printf("%s: no memory for tx list", sc->sc_dev.dv_xname);
+ printf("%s: no memory for tx list\n",
+ sc->sc_dev.dv_xname);
return(1);
}
@@ -1153,7 +1188,7 @@ int sf_encap(sc, c, m_head)
MCLGET(m_new, M_DONTWAIT);
if (!(m_new->m_flags & M_EXT)) {
m_freem(m_new);
- printf("%s: no memory for tx list",
+ printf("%s: no memory for tx list\n",
sc->sc_dev.dv_xname);
return(1);
}
@@ -1189,7 +1224,7 @@ void sf_start(ifp)
sc = ifp->if_softc;
- if (!sc->sf_link)
+ if (!sc->sf_link && ifp->if_snd.ifq_len < 10)
return;
if (ifp->if_flags & IFF_OACTIVE)
@@ -1198,7 +1233,19 @@ void sf_start(ifp)
txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
i = SF_IDX_HI(txprod) >> 4;
+ if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
+ printf("%s: TX ring full, resetting\n", sc->sc_dev.dv_xname);
+ sf_init(sc);
+ txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
+ i = SF_IDX_HI(txprod) >> 4;
+ }
+
while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
+ if (sc->sf_tx_cnt >= (SF_TX_DLIST_CNT - 5)) {
+ ifp->if_flags |= IFF_OACTIVE;
+ cur_tx = NULL;
+ break;
+ }
IFQ_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
@@ -1220,7 +1267,10 @@ void sf_start(ifp)
SF_INC(i, SF_TX_DLIST_CNT);
sc->sf_tx_cnt++;
- if (sc->sf_tx_cnt == (SF_TX_DLIST_CNT - 2))
+ /*
+ * Don't let the TX DMA queue get too full.
+ */
+ if (sc->sf_tx_cnt > 64)
break;
}
diff --git a/sys/dev/pci/if_sfreg.h b/sys/dev/pci/if_sfreg.h
index 75df0d267b9..a10454d5810 100644
--- a/sys/dev/pci/if_sfreg.h
+++ b/sys/dev/pci/if_sfreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sfreg.h,v 1.7 2004/05/19 11:37:00 brad Exp $ */
+/* $OpenBSD: if_sfreg.h,v 1.8 2004/06/01 02:43:28 tedu Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
@@ -346,7 +346,8 @@
(SF_IMR_RXDQ2_NOBUFS|SF_IMR_RXDQ1_DMADONE|SF_IMR_RXDQ2_DMADONE| \
SF_IMR_TX_TXDONE|SF_IMR_RXDQ1_NOBUFS|SF_IMR_RXDQ2_DMADONE| \
SF_IMR_NORMALINTR|SF_IMR_ABNORMALINTR|SF_IMR_TXCQ_NOBUFS| \
- SF_IMR_RXCQ1_NOBUFS|SF_IMR_RXCQ2_NOBUFS|SF_IMR_STATSOFLOW)
+ SF_IMR_RXCQ1_NOBUFS|SF_IMR_RXCQ2_NOBUFS|SF_IMR_STATSOFLOW| \
+ SF_IMR_TX_LOFIFO)
/* TX descriptor queue control registers */
#define SF_TXDQCTL_DESCTYPE 0x00000007