Subject: kern/31837: sip driver receive buffer overrun diminishes the receive capabilities of the driver
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <john32979@gmail.com>
List: netbsd-bugs
Date: 10/16/2005 17:46:00
>Number: 31837
>Category: kern
>Synopsis: sip driver receive buffer overrun diminishes the receive capabilities of the driver
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Oct 16 17:46:00 +0000 2005
>Originator: John Yau
>Release: NetBSD 2.0
>Organization:
>Environment:
>Description:
After a receive buffer overrun, the throughput of the sip interface halves. Setting the buffer ownership back to the sip card if the device is idle after detecting a buffer overrun seems to fix the problem.
>How-To-Repeat:
Trigger a receive buffer overrun by sending large amounts of data on a PC Engines WRAP board. After recovering from the buffer overrun, performance degrades severely.
>Fix:
Index: if_sip.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_sip.c,v
retrieving revision 1.87.2.1
diff -u -r1.87.2.1 if_sip.c
--- if_sip.c 28 May 2004 07:10:38 -0000 1.87.2.1
+++ if_sip.c 16 Oct 2005 17:38:54 -0000
@@ -1504,8 +1504,10 @@
{
struct sip_softc *sc = arg;
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
- u_int32_t isr;
+ u_int32_t isr, cmdsts;
int handled = 0;
+ int i;
+ struct sip_rxsoft *rxs;
for (;;) {
/* Reading clears interrupt. */
@@ -1536,7 +1538,35 @@
if (isr & ISR_RXIDLE) {
printf("%s: receive ring overrun\n",
sc->sc_dev.dv_xname);
-
+ /* jyau
+ *
+ * Go through the receive descriptors and
+ * reset the ownership back to the card.
+ * We drop all the packets currently in the
+ * receive queue.
+ */
+ for (i = sc->sc_rxptr;; i = SIP_NEXTRX(i)) {
+ rxs = &sc->sc_rxsoft[i];
+ SIP_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ cmdsts = le32toh(sc->sc_rxdescs[i].sipd_cmdsts);
+ /*
+ * NOTE: OWN is set if owned by _consumer_. We're the
+ * consumer of the receive ring, so if the bit is clear,
+ * we have processed all of the packets.
+ */
+ if ((cmdsts & CMDSTS_OWN) == 0) {
+ /*
+ * We have processed all of the receive buffers.
+ */
+ break;
+ }
+ ifp->if_ierrors++;
+ SIP_INIT_RXDESC(sc, i);
+ bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
+ rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+ printf("%s, Cleared rx desc %d\n",
+ sc->sc_dev.dv_xname, i);
+ }
/* Get the receive process going again. */
bus_space_write_4(sc->sc_st, sc->sc_sh,
SIP_RXDP, SIP_CDRXADDR(sc, sc->sc_rxptr));